mirror of
				https://github.com/rad4day/Waybar.git
				synced 2025-10-31 07:52:42 +01:00 
			
		
		
		
	Merge branch 'master' into YearCalendar
Signed-off-by: Viktar Lukashonak <myxabeer@gmail.com>
This commit is contained in:
		
							
								
								
									
										2
									
								
								.github/workflows/freebsd.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/freebsd.yml
									
									
									
									
										vendored
									
									
								
							| @@ -9,7 +9,7 @@ jobs: | ||||
|     # https://github.com/actions/virtual-environments/issues/4060 - for lack of VirtualBox on MacOS 11 runners | ||||
|     runs-on: macos-12 | ||||
|     steps: | ||||
|     - uses: actions/checkout@v2 | ||||
|     - uses: actions/checkout@v3 | ||||
|     - name: Test in FreeBSD VM | ||||
|       uses: vmactions/freebsd-vm@v0 | ||||
|       with: | ||||
|   | ||||
							
								
								
									
										2
									
								
								.github/workflows/lint.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/lint.yml
									
									
									
									
										vendored
									
									
								
							| @@ -6,7 +6,7 @@ jobs: | ||||
|   build: | ||||
|     runs-on: ubuntu-latest | ||||
|     steps: | ||||
|     - uses: actions/checkout@v2 | ||||
|     - uses: actions/checkout@v3 | ||||
|     - uses: DoozyX/clang-format-lint-action@v0.13 | ||||
|       with: | ||||
|         source: '.' | ||||
|   | ||||
							
								
								
									
										10
									
								
								.github/workflows/linux.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										10
									
								
								.github/workflows/linux.yml
									
									
									
									
										vendored
									
									
								
							| @@ -13,16 +13,20 @@ jobs: | ||||
|           - fedora | ||||
|           - opensuse | ||||
|           - gentoo | ||||
|         cpp_std: [c++17] | ||||
|         include: | ||||
|           - distro: fedora | ||||
|             cpp_std: c++20 | ||||
|  | ||||
|     runs-on: ubuntu-latest | ||||
|     container: | ||||
|       image: alexays/waybar:${{ matrix.distro }} | ||||
|  | ||||
|     steps: | ||||
|       - uses: actions/checkout@v2 | ||||
|       - uses: actions/checkout@v3 | ||||
|       - name: configure | ||||
|         run: meson -Dman-pages=enabled build | ||||
|         run: meson -Dman-pages=enabled -Dcpp_std=${{matrix.cpp_std}} build | ||||
|       - name: build | ||||
|         run: ninja -C build | ||||
|       - name: test | ||||
|         run: meson test -C build --no-rebuild --print-errorlogs --suite waybar | ||||
|         run: meson test -C build --no-rebuild --verbose --suite waybar | ||||
|   | ||||
| @@ -3,4 +3,5 @@ | ||||
| FROM archlinux:base-devel | ||||
|  | ||||
| RUN pacman -Syu --noconfirm && \ | ||||
|     pacman -S --noconfirm git meson base-devel libinput wayland wayland-protocols pixman libxkbcommon mesa gtkmm3 jsoncpp pugixml scdoc libpulse libdbusmenu-gtk3 libmpdclient gobject-introspection libxkbcommon playerctl | ||||
|     pacman -S --noconfirm git meson base-devel libinput wayland wayland-protocols pixman libxkbcommon mesa gtkmm3 jsoncpp pugixml scdoc libpulse libdbusmenu-gtk3 libmpdclient gobject-introspection libxkbcommon playerctl && \ | ||||
|     sed -Ei 's/#(en_(US|GB)\.UTF)/\1/' /etc/locale.gen && locale-gen | ||||
|   | ||||
| @@ -2,12 +2,33 @@ | ||||
|  | ||||
| FROM fedora:latest | ||||
|  | ||||
| RUN dnf install -y @c-development git-core meson scdoc 'pkgconfig(date)' \ | ||||
|     'pkgconfig(dbusmenu-gtk3-0.4)' 'pkgconfig(fmt)' 'pkgconfig(gdk-pixbuf-2.0)' \ | ||||
|     'pkgconfig(gio-unix-2.0)' 'pkgconfig(gtk-layer-shell-0)' 'pkgconfig(gtkmm-3.0)' \ | ||||
|     'pkgconfig(jsoncpp)' 'pkgconfig(libinput)' 'pkgconfig(libmpdclient)' \ | ||||
|     'pkgconfig(libnl-3.0)' 'pkgconfig(libnl-genl-3.0)' 'pkgconfig(libpulse)' \ | ||||
|     'pkgconfig(libudev)' 'pkgconfig(pugixml)' 'pkgconfig(sigc++-2.0)' 'pkgconfig(spdlog)' \ | ||||
|     'pkgconfig(wayland-client)' 'pkgconfig(wayland-cursor)' 'pkgconfig(wayland-protocols)' 'pkgconfig(xkbregistry)' \ | ||||
|     'pkgconfig(playerctl)' && \ | ||||
| RUN dnf install -y @c-development \ | ||||
|     git-core glibc-langpack-en meson scdoc \ | ||||
|     'pkgconfig(catch2)' \ | ||||
|     'pkgconfig(date)' \ | ||||
|     'pkgconfig(dbusmenu-gtk3-0.4)' \ | ||||
|     'pkgconfig(fmt)' \ | ||||
|     'pkgconfig(gdk-pixbuf-2.0)' \ | ||||
|     'pkgconfig(gio-unix-2.0)' \ | ||||
|     'pkgconfig(gtk-layer-shell-0)' \ | ||||
|     'pkgconfig(gtkmm-3.0)' \ | ||||
|     'pkgconfig(jack)' \ | ||||
|     'pkgconfig(jsoncpp)' \ | ||||
|     'pkgconfig(libevdev)' \ | ||||
|     'pkgconfig(libinput)' \ | ||||
|     'pkgconfig(libmpdclient)' \ | ||||
|     'pkgconfig(libnl-3.0)' \ | ||||
|     'pkgconfig(libnl-genl-3.0)' \ | ||||
|     'pkgconfig(libpulse)' \ | ||||
|     'pkgconfig(libudev)' \ | ||||
|     'pkgconfig(playerctl)' \ | ||||
|     'pkgconfig(pugixml)' \ | ||||
|     'pkgconfig(sigc++-2.0)' \ | ||||
|     'pkgconfig(spdlog)' \ | ||||
|     'pkgconfig(upower-glib)' \ | ||||
|     'pkgconfig(wayland-client)' \ | ||||
|     'pkgconfig(wayland-cursor)' \ | ||||
|     'pkgconfig(wayland-protocols)' \ | ||||
|     'pkgconfig(wireplumber-0.4)' \ | ||||
|     'pkgconfig(xkbregistry)' && \ | ||||
|     dnf clean all -y | ||||
|   | ||||
| @@ -15,6 +15,7 @@ class AModule : public IModule { | ||||
|           bool enable_scroll = false); | ||||
|   virtual ~AModule(); | ||||
|   virtual auto update() -> void; | ||||
|   virtual auto refresh(int) -> void{}; | ||||
|   virtual operator Gtk::Widget &(); | ||||
|  | ||||
|   Glib::Dispatcher dp; | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include <json/json.h> | ||||
| #ifdef HAVE_LIBDATE | ||||
| #if defined(HAVE_CHRONO_TIMEZONES) || defined(HAVE_LIBDATE) | ||||
| #include "modules/clock.hpp" | ||||
| #else | ||||
| #include "modules/simpleclock.hpp" | ||||
|   | ||||
| @@ -1,19 +1,25 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include <date/tz.h> | ||||
|  | ||||
| #include "ALabel.hpp" | ||||
| #include "util/date.hpp" | ||||
| #include "util/sleeper_thread.hpp" | ||||
|  | ||||
| namespace waybar { | ||||
|  | ||||
| struct waybar_time; | ||||
|  | ||||
| namespace modules { | ||||
| namespace waybar::modules { | ||||
|  | ||||
| const std::string kCalendarPlaceholder = "calendar"; | ||||
| const std::string KTimezonedTimeListPlaceholder = "timezoned_time_list"; | ||||
|  | ||||
| enum class WeeksSide { | ||||
|   LEFT, | ||||
|   RIGHT, | ||||
|   HIDDEN, | ||||
| }; | ||||
|  | ||||
| enum class CldMode { | ||||
|   MONTH, | ||||
|   YEAR | ||||
| }; | ||||
|  | ||||
| class Clock : public ALabel { | ||||
|  public: | ||||
|   Clock(const std::string&, const Json::Value&); | ||||
| @@ -22,26 +28,37 @@ class Clock : public ALabel { | ||||
|  | ||||
|  private: | ||||
|   util::SleeperThread thread_; | ||||
|   std::map<std::pair<uint, GdkEventType>, void (waybar::modules::Clock::*)()> eventMap_; | ||||
|   std::locale locale_; | ||||
|   std::vector<const date::time_zone*> time_zones_; | ||||
|   int current_time_zone_idx_; | ||||
|   date::year_month_day calendar_cached_ymd_{date::January / 1 / 0}; | ||||
|   date::months calendar_shift_{0}, calendar_shift_init_{0}; | ||||
|   std::string calendar_cached_text_; | ||||
|   bool is_calendar_in_tooltip_; | ||||
|   bool is_timezoned_list_in_tooltip_; | ||||
|  | ||||
|   bool handleScroll(GdkEventScroll* e); | ||||
|   bool handleToggle(GdkEventButton* const& e); | ||||
|  | ||||
|   std::string fmt_str_weeks_; | ||||
|   std::string fmt_str_calendar_; | ||||
|   int fmt_weeks_left_pad_{0}; | ||||
|   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; | ||||
|   const date::time_zone* current_timezone(); | ||||
|   bool is_timezone_fixed(); | ||||
|   auto timezones_text(std::chrono::system_clock::time_point* now) -> std::string; | ||||
|  | ||||
|   /*Calendar properties*/ | ||||
|   WeeksSide cldWPos_{WeeksSide::HIDDEN}; | ||||
|   std::map<int, std::string const> fmtMap_; | ||||
|   CldMode cldMode_{CldMode::MONTH}; | ||||
|   uint cldMonCols_{3}; // Count of the month in the row | ||||
|   int cldMonColLen_{20}; // Length of the month column | ||||
|   int cldWnLen_{2}; // Length of the week number | ||||
|   date::year_month_day cldYearShift_; | ||||
|   date::year_month cldMonShift_; | ||||
|   date::months cldCurrShift_{0}; | ||||
|   date::months cldShift_{0}; | ||||
|   std::string cldYearCached_{}; | ||||
|   std::string cldMonCached_{}; | ||||
|   /*Calendar functions*/ | ||||
|   auto get_calendar(const date::zoned_seconds& now, | ||||
|                     const date::zoned_seconds& wtime) -> std::string; | ||||
|   void cldModeSwitch(); | ||||
| }; | ||||
| }  // namespace modules | ||||
| }  // namespace waybar | ||||
| }  // namespace waybar::modules | ||||
|   | ||||
| @@ -8,6 +8,7 @@ | ||||
| #include <cstring> | ||||
| #include <memory> | ||||
| #include <mutex> | ||||
| #include <string> | ||||
|  | ||||
| #include "ipc.hpp" | ||||
| #include "util/sleeper_thread.hpp" | ||||
|   | ||||
| @@ -4,6 +4,7 @@ | ||||
| #include <gtkmm/button.h> | ||||
| #include <gtkmm/label.h> | ||||
|  | ||||
| #include <string_view> | ||||
| #include <unordered_map> | ||||
|  | ||||
| #include "AModule.hpp" | ||||
| @@ -21,7 +22,9 @@ class Workspaces : public AModule, public sigc::trackable { | ||||
|   auto update() -> void; | ||||
|  | ||||
|  private: | ||||
|   static inline const std::string workspace_switch_cmd_ = "workspace {} \"{}\""; | ||||
|   static constexpr std::string_view workspace_switch_cmd_ = "workspace {} \"{}\""; | ||||
|   static constexpr std::string_view persistent_workspace_switch_cmd_ = | ||||
|       R"(workspace {} "{}"; move workspace to output "{}"; workspace {} "{}")"; | ||||
|  | ||||
|   static int convertWorkspaceNameToNum(std::string name); | ||||
|  | ||||
|   | ||||
							
								
								
									
										60
									
								
								include/util/date.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								include/util/date.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,60 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include <fmt/format.h> | ||||
|  | ||||
| #if HAVE_CHRONO_TIMEZONES | ||||
| #include <chrono> | ||||
| #include <format> | ||||
|  | ||||
| /* Compatibility layer for <date/tz.h> on top of C++20 <chrono> */ | ||||
| namespace date { | ||||
|  | ||||
| using namespace std::chrono; | ||||
|  | ||||
| namespace literals { | ||||
| using std::chrono::last; | ||||
| } | ||||
|  | ||||
| inline auto format(const std::string& spec, const auto& ztime) { | ||||
|   return spec.empty() ? "" : std::vformat("{:L" + spec + "}", std::make_format_args(ztime)); | ||||
| } | ||||
|  | ||||
| inline auto format(const std::locale& loc, const std::string& spec, const auto& ztime) { | ||||
|   return spec.empty() ? "" : std::vformat(loc, "{:L" + spec + "}", std::make_format_args(ztime)); | ||||
| } | ||||
|  | ||||
| }  // namespace date | ||||
|  | ||||
| #else | ||||
| #include <date/tz.h> | ||||
| #endif | ||||
|  | ||||
| template <typename Duration, typename TimeZonePtr> | ||||
| struct fmt::formatter<date::zoned_time<Duration, TimeZonePtr>> { | ||||
|   std::string_view specs; | ||||
|  | ||||
|   template <typename ParseContext> | ||||
|   constexpr auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { | ||||
|     auto it = ctx.begin(); | ||||
|     if (it != ctx.end() && *it == ':') { | ||||
|       ++it; | ||||
|     } | ||||
|     auto end = it; | ||||
|     while (end != ctx.end() && *end != '}') { | ||||
|       ++end; | ||||
|     } | ||||
|     if (end != it) { | ||||
|       specs = {it, std::string_view::size_type(end - it)}; | ||||
|     } | ||||
|     return end; | ||||
|   } | ||||
|  | ||||
|   template <typename FormatContext> | ||||
|   auto format(const date::zoned_time<Duration, TimeZonePtr>& ztime, FormatContext& ctx) { | ||||
|     if (ctx.locale()) { | ||||
|       const auto loc = ctx.locale().template get<std::locale>(); | ||||
|       return fmt::format_to(ctx.out(), "{}", date::format(loc, fmt::to_string(specs), ztime)); | ||||
|     } | ||||
|     return fmt::format_to(ctx.out(), "{}", date::format(fmt::to_string(specs), ztime)); | ||||
|   } | ||||
| }; | ||||
| @@ -66,9 +66,9 @@ struct formatter<pow_format> { | ||||
|     std::string string; | ||||
|     switch (spec) { | ||||
|       case '>': | ||||
|         return format_to(ctx.out(), "{:>{}}", fmt::format("{}", s), max_width); | ||||
|         return fmt::format_to(ctx.out(), "{:>{}}", fmt::format("{}", s), max_width); | ||||
|       case '<': | ||||
|         return format_to(ctx.out(), "{:<{}}", fmt::format("{}", s), max_width); | ||||
|         return fmt::format_to(ctx.out(), "{:<{}}", fmt::format("{}", s), max_width); | ||||
|       case '=': | ||||
|         format = "{coefficient:<{number_width}.1f}{padding}{prefix}{unit}"; | ||||
|         break; | ||||
| @@ -77,8 +77,8 @@ struct formatter<pow_format> { | ||||
|         format = "{coefficient:.1f}{prefix}{unit}"; | ||||
|         break; | ||||
|     } | ||||
|     return format_to( | ||||
|         ctx.out(), format, fmt::arg("coefficient", fraction), | ||||
|     return fmt::format_to( | ||||
|         ctx.out(), fmt::runtime(format), fmt::arg("coefficient", fraction), | ||||
|         fmt::arg("number_width", number_width), | ||||
|         fmt::arg("prefix", std::string() + units[pow] + ((s.binary_ && pow) ? "i" : "")), | ||||
|         fmt::arg("unit", s.unit_), | ||||
|   | ||||
| @@ -1,39 +0,0 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include <date/tz.h> | ||||
| #include <fmt/format.h> | ||||
|  | ||||
| namespace waybar { | ||||
|  | ||||
| struct waybar_time { | ||||
|   std::locale locale; | ||||
|   date::zoned_seconds ztime; | ||||
| }; | ||||
|  | ||||
| }  // namespace waybar | ||||
|  | ||||
| template <> | ||||
| struct fmt::formatter<waybar::waybar_time> { | ||||
|   std::string_view specs; | ||||
|  | ||||
|   template <typename ParseContext> | ||||
|   constexpr auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { | ||||
|     auto it = ctx.begin(); | ||||
|     if (it != ctx.end() && *it == ':') { | ||||
|       ++it; | ||||
|     } | ||||
|     auto end = it; | ||||
|     while (end != ctx.end() && *end != '}') { | ||||
|       ++end; | ||||
|     } | ||||
|     if (end != it) { | ||||
|       specs = {it, std::string_view::size_type(end - it)}; | ||||
|     } | ||||
|     return end; | ||||
|   } | ||||
|  | ||||
|   template <typename FormatContext> | ||||
|   auto format(const waybar::waybar_time& t, FormatContext& ctx) { | ||||
|     return format_to(ctx.out(), "{}", date::format(t.locale, fmt::to_string(specs), t.ztime)); | ||||
|   } | ||||
| }; | ||||
| @@ -1,4 +1,4 @@ | ||||
| waybar-custom(5) | ||||
| waybar-image(5) | ||||
|  | ||||
| # NAME | ||||
|  | ||||
| @@ -69,4 +69,4 @@ Addressed by *custom/<name>* | ||||
| 	"interval": 5, | ||||
| 	"on-click": "mpc toggle" | ||||
| } | ||||
| ``` | ||||
| ``` | ||||
|   | ||||
| @@ -263,6 +263,7 @@ A module group is defined by specifying a module named "group/some-group-name". | ||||
| - *waybar-custom(5)* | ||||
| - *waybar-disk(5)* | ||||
| - *waybar-idle-inhibitor(5)* | ||||
| - *waybar-image(5)* | ||||
| - *waybar-keyboard-state(5)* | ||||
| - *waybar-memory(5)* | ||||
| - *waybar-mpd(5)* | ||||
|   | ||||
							
								
								
									
										25
									
								
								meson.build
									
									
									
									
									
								
							
							
						
						
									
										25
									
								
								meson.build
									
									
									
									
									
								
							| @@ -123,11 +123,18 @@ 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', | ||||
|     required: false, | ||||
|     default_options : [ 'use_system_tzdb=true' ], | ||||
|     modules : [ 'date::date', 'date::date-tz' ], | ||||
|     fallback: [ 'date', 'tz_dep' ]) | ||||
|  | ||||
| cpp_lib_chrono = compiler.compute_int('__cpp_lib_chrono', prefix : '#include <chrono>') | ||||
| have_chrono_timezones = cpp_lib_chrono >= 201907 | ||||
| if have_chrono_timezones | ||||
|   tz_dep = declare_dependency() | ||||
| else | ||||
|   tz_dep = dependency('date', | ||||
|       required: false, | ||||
|       default_options : [ 'use_system_tzdb=true' ], | ||||
|       modules : [ 'date::date', 'date::date-tz' ], | ||||
|       fallback: [ 'date', 'tz_dep' ]) | ||||
| endif | ||||
|  | ||||
| prefix = get_option('prefix') | ||||
| sysconfdir = get_option('sysconfdir') | ||||
| @@ -312,7 +319,10 @@ if get_option('rfkill').enabled() and is_linux | ||||
|     ) | ||||
| endif | ||||
|  | ||||
| if tz_dep.found() | ||||
| if have_chrono_timezones | ||||
|     add_project_arguments('-DHAVE_CHRONO_TIMEZONES', language: 'cpp') | ||||
|     src_files += 'src/modules/clock.cpp' | ||||
| elif tz_dep.found() | ||||
|     add_project_arguments('-DHAVE_LIBDATE', language: 'cpp') | ||||
|     src_files += 'src/modules/clock.cpp' | ||||
| else | ||||
| @@ -395,6 +405,7 @@ if scdoc.found() | ||||
|         'waybar-disk.5.scd', | ||||
|         'waybar-gamemode.5.scd', | ||||
|         'waybar-idle-inhibitor.5.scd', | ||||
|         'waybar-image.5.scd', | ||||
|         'waybar-keyboard-state.5.scd', | ||||
|         'waybar-memory.5.scd', | ||||
|         'waybar-mpd.5.scd', | ||||
| @@ -447,7 +458,7 @@ endif | ||||
|  | ||||
| catch2 = dependency( | ||||
|     'catch2', | ||||
|     version: '>=3.0.0', | ||||
|     version: '>=2.0.0', | ||||
|     fallback: ['catch2', 'catch2_dep'], | ||||
|     required: get_option('tests'), | ||||
| ) | ||||
|   | ||||
| @@ -725,10 +725,7 @@ void waybar::Bar::setupAltFormatKeyForModuleList(const char* module_list_name) { | ||||
|  | ||||
| void waybar::Bar::handleSignal(int signal) { | ||||
|   for (auto& module : modules_all_) { | ||||
|     auto* custom = dynamic_cast<waybar::modules::Custom*>(module.get()); | ||||
|     if (custom != nullptr) { | ||||
|       custom->refresh(signal); | ||||
|     } | ||||
|     module->refresh(signal); | ||||
|   } | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -48,13 +48,13 @@ struct UdevMonitorDeleter { | ||||
|  | ||||
| void check_eq(int rc, int expected, const char *message = "eq, rc was: ") { | ||||
|   if (rc != expected) { | ||||
|     throw std::runtime_error(fmt::format(message, rc)); | ||||
|     throw std::runtime_error(fmt::format(fmt::runtime(message), rc)); | ||||
|   } | ||||
| } | ||||
|  | ||||
| void check_neq(int rc, int bad_rc, const char *message = "neq, rc was: ") { | ||||
|   if (rc == bad_rc) { | ||||
|     throw std::runtime_error(fmt::format(message, rc)); | ||||
|     throw std::runtime_error(fmt::format(fmt::runtime(message), rc)); | ||||
|   } | ||||
| } | ||||
|  | ||||
| @@ -62,7 +62,7 @@ void check0(int rc, const char *message = "rc wasn't 0") { check_eq(rc, 0, messa | ||||
|  | ||||
| void check_gte(int rc, int gte, const char *message = "rc was: ") { | ||||
|   if (rc < gte) { | ||||
|     throw std::runtime_error(fmt::format(message, rc)); | ||||
|     throw std::runtime_error(fmt::format(fmt::runtime(message), rc)); | ||||
|   } | ||||
| } | ||||
|  | ||||
| @@ -181,7 +181,8 @@ auto waybar::modules::Backlight::update() -> void { | ||||
|       event_box_.show(); | ||||
|       const uint8_t percent = | ||||
|           best->get_max() == 0 ? 100 : round(best->get_actual() * 100.0f / best->get_max()); | ||||
|       label_.set_markup(fmt::format(format_, fmt::arg("percent", std::to_string(percent)), | ||||
|       label_.set_markup(fmt::format(fmt::runtime(format_), | ||||
|                                     fmt::arg("percent", std::to_string(percent)), | ||||
|                                     fmt::arg("icon", getIcon(percent)))); | ||||
|       getState(percent); | ||||
|     } else { | ||||
|   | ||||
| @@ -604,7 +604,7 @@ const std::string waybar::modules::Battery::formatTimeRemaining(float hoursRemai | ||||
|     format = config_["format-time"].asString(); | ||||
|   } | ||||
|   std::string zero_pad_minutes = fmt::format("{:02d}", minutes); | ||||
|   return fmt::format(format, fmt::arg("H", full_hours), fmt::arg("M", minutes), | ||||
|   return fmt::format(fmt::runtime(format), fmt::arg("H", full_hours), fmt::arg("M", minutes), | ||||
|                      fmt::arg("m", zero_pad_minutes)); | ||||
| } | ||||
|  | ||||
| @@ -644,7 +644,8 @@ auto waybar::modules::Battery::update() -> void { | ||||
|     } else if (config_["tooltip-format"].isString()) { | ||||
|       tooltip_format = config_["tooltip-format"].asString(); | ||||
|     } | ||||
|     label_.set_tooltip_text(fmt::format(tooltip_format, fmt::arg("timeTo", tooltip_text_default), | ||||
|     label_.set_tooltip_text(fmt::format(fmt::runtime(tooltip_format), | ||||
|                                         fmt::arg("timeTo", tooltip_text_default), | ||||
|                                         fmt::arg("power", power), fmt::arg("capacity", capacity), | ||||
|                                         fmt::arg("time", time_remaining_formatted))); | ||||
|   } | ||||
| @@ -665,9 +666,9 @@ auto waybar::modules::Battery::update() -> void { | ||||
|   } else { | ||||
|     event_box_.show(); | ||||
|     auto icons = std::vector<std::string>{status + "-" + state, status, state}; | ||||
|     label_.set_markup(fmt::format(format, fmt::arg("capacity", capacity), fmt::arg("power", power), | ||||
|                                   fmt::arg("icon", getIcon(capacity, icons)), | ||||
|                                   fmt::arg("time", time_remaining_formatted))); | ||||
|     label_.set_markup(fmt::format( | ||||
|         fmt::runtime(format), fmt::arg("capacity", capacity), fmt::arg("power", power), | ||||
|         fmt::arg("icon", getIcon(capacity, icons)), fmt::arg("time", time_remaining_formatted))); | ||||
|   } | ||||
|   // Call parent update | ||||
|   ALabel::update(); | ||||
|   | ||||
| @@ -206,7 +206,8 @@ auto waybar::modules::Bluetooth::update() -> void { | ||||
|   state_ = state; | ||||
|  | ||||
|   label_.set_markup(fmt::format( | ||||
|       format_, fmt::arg("status", state_), fmt::arg("num_connections", connected_devices_.size()), | ||||
|       fmt::runtime(format_), fmt::arg("status", state_), | ||||
|       fmt::arg("num_connections", connected_devices_.size()), | ||||
|       fmt::arg("controller_address", cur_controller_.address), | ||||
|       fmt::arg("controller_address_type", cur_controller_.address_type), | ||||
|       fmt::arg("controller_alias", cur_controller_.alias), | ||||
| @@ -234,7 +235,7 @@ auto waybar::modules::Bluetooth::update() -> void { | ||||
|             enumerate_format = config_["tooltip-format-enumerate-connected"].asString(); | ||||
|           } | ||||
|           ss << fmt::format( | ||||
|               enumerate_format, fmt::arg("device_address", dev.address), | ||||
|               fmt::runtime(enumerate_format), fmt::arg("device_address", dev.address), | ||||
|               fmt::arg("device_address_type", dev.address_type), | ||||
|               fmt::arg("device_alias", dev.alias), fmt::arg("icon", enumerate_icon), | ||||
|               fmt::arg("device_battery_percentage", dev.battery_percentage.value_or(0))); | ||||
| @@ -247,7 +248,7 @@ auto waybar::modules::Bluetooth::update() -> void { | ||||
|       } | ||||
|     } | ||||
|     label_.set_tooltip_text(fmt::format( | ||||
|         tooltip_format, fmt::arg("status", state_), | ||||
|         fmt::runtime(tooltip_format), fmt::arg("status", state_), | ||||
|         fmt::arg("num_connections", connected_devices_.size()), | ||||
|         fmt::arg("controller_address", cur_controller_.address), | ||||
|         fmt::arg("controller_address_type", cur_controller_.address_type), | ||||
|   | ||||
| @@ -10,14 +10,11 @@ | ||||
| #include <type_traits> | ||||
|  | ||||
| #include "util/ustring_clen.hpp" | ||||
| #include "util/waybar_time.hpp" | ||||
| #ifdef HAVE_LANGINFO_1STDAY | ||||
| #include <langinfo.h> | ||||
| #include <locale.h> | ||||
| #endif | ||||
|  | ||||
| using waybar::waybar_time; | ||||
|  | ||||
| waybar::modules::Clock::Clock(const std::string& id, const Json::Value& config) | ||||
|     : ALabel(config, "clock", id, "{:%H:%M}", 60, false, false, true), | ||||
|       current_time_zone_idx_(0), | ||||
| @@ -41,12 +38,6 @@ waybar::modules::Clock::Clock(const std::string& id, const Json::Value& config) | ||||
|     time_zones_.push_back(nullptr); | ||||
|   } | ||||
|  | ||||
|   if (!is_timezone_fixed()) { | ||||
|     spdlog::warn( | ||||
|         "As using a timezone, some format args may be missing as the date library haven't got a " | ||||
|         "release since 2018."); | ||||
|   } | ||||
|  | ||||
|   // Check if a particular placeholder is present in the tooltip format, to know what to calculate | ||||
|   // on update. | ||||
|   if (config_["tooltip-format"].isString()) { | ||||
| @@ -62,39 +53,98 @@ waybar::modules::Clock::Clock(const std::string& id, const Json::Value& config) | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   // Calendar configuration | ||||
|   if (is_calendar_in_tooltip_) { | ||||
|     if (config_["on-scroll"][kCalendarPlaceholder].isInt()) { | ||||
|       calendar_shift_init_ = | ||||
|           date::months{config_["on-scroll"].get(kCalendarPlaceholder, 0).asInt()}; | ||||
|     if (config_[kCalendarPlaceholder]["weeks-pos"].isString()) { | ||||
|       if (config_[kCalendarPlaceholder]["weeks-pos"].asString() == "left") { | ||||
|         cldWPos_ = WeeksSide::LEFT; | ||||
|       } else if (config_[kCalendarPlaceholder]["weeks-pos"].asString() == "right") { | ||||
|         cldWPos_ = WeeksSide::RIGHT; | ||||
|       } | ||||
|     } | ||||
|     if (config_[kCalendarPlaceholder]["format"]["months"].isString()) | ||||
|       fmtMap_.insert({0, config_[kCalendarPlaceholder]["format"]["months"].asString()}); | ||||
|     else | ||||
|       fmtMap_.insert({0, "{}"}); | ||||
|     if (config_[kCalendarPlaceholder]["format"]["days"].isString()) | ||||
|       fmtMap_.insert({2, config_[kCalendarPlaceholder]["format"]["days"].asString()}); | ||||
|     else | ||||
|       fmtMap_.insert({2, "{}"}); | ||||
|     if (config_[kCalendarPlaceholder]["format"]["weeks"].isString()) { | ||||
|       fmtMap_.insert( | ||||
|           {4, std::regex_replace(config_[kCalendarPlaceholder]["format"]["weeks"].asString(), | ||||
|                                  std::regex("\\{\\}"), | ||||
|                                  (first_day_of_week() == date::Monday) ? "{:%W}" : "{:%U}")}); | ||||
|  | ||||
|       if (cldWPos_ == WeeksSide::HIDDEN) | ||||
|         cldWnLen_ = 0; | ||||
|       else { | ||||
|         // tmp contains full length of the weeks including user characters | ||||
|         Glib::ustring tmp{std::regex_replace(fmtMap_[4], std::regex("</?[^>]+>|\\{.*\\}"), "")}; | ||||
|         cldWnLen_ += (tmp.size() + 1); | ||||
|         cldMonColLen_ += cldWnLen_; | ||||
|       } | ||||
|     } else { | ||||
|       if (cldWPos_ != WeeksSide::HIDDEN) | ||||
|         fmtMap_.insert({4, (first_day_of_week() == date::Monday) ? "{:%W}" : "{:%U}"}); | ||||
|     } | ||||
|     if (config_[kCalendarPlaceholder]["format"]["weekdays"].isString()) | ||||
|       fmtMap_.insert({1, config_[kCalendarPlaceholder]["format"]["weekdays"].asString()}); | ||||
|     else | ||||
|       fmtMap_.insert({1, "{}"}); | ||||
|     if (config_[kCalendarPlaceholder]["format"]["today"].isString()) | ||||
|       fmtMap_.insert({3, config_[kCalendarPlaceholder]["format"]["today"].asString()}); | ||||
|     else | ||||
|       fmtMap_.insert({3, "{}"}); | ||||
|     if (config_[kCalendarPlaceholder]["mode"].isString()) { | ||||
|       const std::string cfgMode{(config_[kCalendarPlaceholder]["mode"].isString()) | ||||
|                                     ? config_[kCalendarPlaceholder]["mode"].asString() | ||||
|                                     : "month"}; | ||||
|       const std::map<std::string, const CldMode&> monthModes{{"month", CldMode::MONTH}, | ||||
|                                                              {"year", CldMode::YEAR}}; | ||||
|       if (monthModes.find(cfgMode) != monthModes.end()) | ||||
|         cldMode_ = monthModes.at(cfgMode); | ||||
|       else | ||||
|         spdlog::warn( | ||||
|             "Clock calendar configuration \"mode\"\"\" \"{0}\" is not recognized. Mode = \"month\" " | ||||
|             "is using instead", | ||||
|             cfgMode); | ||||
|     } | ||||
|     if (config_[kCalendarPlaceholder]["mode-mon-col"].isInt()) { | ||||
|       cldMonCols_ = config_[kCalendarPlaceholder]["mode-mon-col"].asInt(); | ||||
|       if (cldMonCols_ == 0u || 12 % cldMonCols_ != 0u) { | ||||
|         cldMonCols_ = 3u; | ||||
|         spdlog::warn( | ||||
|             "Clock calendar configuration \"mode-mon-col\" = {0} must be one of [1, 2, 3, 4, 6, " | ||||
|             "12]. Value 3 is using instead", | ||||
|             cldMonCols_); | ||||
|       } | ||||
|     } else | ||||
|       cldMonCols_ = 1; | ||||
|     if (config_[kCalendarPlaceholder]["on-scroll"].isInt()) { | ||||
|       cldShift_ = date::months{config_[kCalendarPlaceholder]["on-scroll"].asInt()}; | ||||
|       event_box_.add_events(Gdk::LEAVE_NOTIFY_MASK); | ||||
|       event_box_.signal_leave_notify_event().connect([this](GdkEventCrossing*) { | ||||
|         calendar_shift_ = date::months{0}; | ||||
|         cldCurrShift_ = date::months{0}; | ||||
|         return false; | ||||
|       }); | ||||
|     } | ||||
|     if (config_[kCalendarPlaceholder]["on-click-left"].isString()) { | ||||
|       if (config_[kCalendarPlaceholder]["on-click-left"].asString() == "mode") | ||||
|         eventMap_.insert({std::make_pair(1, GdkEventType::GDK_BUTTON_PRESS), | ||||
|                           &waybar::modules::Clock::cldModeSwitch}); | ||||
|     } | ||||
|     if (config_[kCalendarPlaceholder]["on-click-right"].isString()) { | ||||
|       if (config_[kCalendarPlaceholder]["on-click-right"].asString() == "mode") | ||||
|         eventMap_.insert({std::make_pair(3, GdkEventType::GDK_BUTTON_PRESS), | ||||
|                           &waybar::modules::Clock::cldModeSwitch}); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   if (config_["locale"].isString()) { | ||||
|   if (config_["locale"].isString()) | ||||
|     locale_ = std::locale(config_["locale"].asString()); | ||||
|   } else { | ||||
|   else | ||||
|     locale_ = std::locale(""); | ||||
|   } | ||||
|  | ||||
|   if (config_["format-calendar-weeks"].isString()) { | ||||
|     fmt_str_weeks_ = | ||||
|         std::regex_replace(config_["format-calendar-weeks"].asString(), std::regex("\\{\\}"), | ||||
|                            (first_day_of_week() == date::Monday) ? "{:%V}" : "{:%U}"); | ||||
|     fmt_weeks_left_pad_ = | ||||
|         std::regex_replace(fmt_str_weeks_, std::regex("</?[^>]+>|\\{.*\\}"), "").length(); | ||||
|   } else { | ||||
|     fmt_str_weeks_ = ""; | ||||
|   } | ||||
|  | ||||
|   if (config_["format-calendar"].isString()) { | ||||
|     fmt_str_calendar_ = config_["format-calendar"].asString(); | ||||
|   } else { | ||||
|     fmt_str_calendar_ = "{}"; | ||||
|   } | ||||
|  | ||||
|   thread_ = [this] { | ||||
|     dp.emit(); | ||||
| @@ -116,24 +166,22 @@ bool waybar::modules::Clock::is_timezone_fixed() { | ||||
| } | ||||
|  | ||||
| auto waybar::modules::Clock::update() -> void { | ||||
|   auto time_zone = current_timezone(); | ||||
|   const auto* time_zone = current_timezone(); | ||||
|   auto now = std::chrono::system_clock::now(); | ||||
|   waybar_time wtime = {locale_, | ||||
|                        date::make_zoned(time_zone, date::floor<std::chrono::seconds>(now))}; | ||||
|   auto ztime = date::zoned_time{time_zone, date::floor<std::chrono::seconds>(now)}; | ||||
|  | ||||
|   auto shifted_date = date::year_month_day{date::floor<date::days>(now)} + calendar_shift_; | ||||
|   auto shifted_date = date::year_month_day{date::floor<date::days>(now)} + cldCurrShift_; | ||||
|   auto now_shifted = date::sys_days{shifted_date} + (now - date::floor<date::days>(now)); | ||||
|   waybar_time shifted_wtime = { | ||||
|       locale_, date::make_zoned(time_zone, date::floor<std::chrono::seconds>(now_shifted))}; | ||||
|   auto shifted_ztime = date::zoned_time{time_zone, date::floor<std::chrono::seconds>(now_shifted)}; | ||||
|  | ||||
|   std::string text = ""; | ||||
|   std::string text{""}; | ||||
|   if (!is_timezone_fixed()) { | ||||
|     // As date dep is not fully compatible, prefer fmt | ||||
|     tzset(); | ||||
|     auto localtime = fmt::localtime(std::chrono::system_clock::to_time_t(now)); | ||||
|     text = fmt::format(locale_, format_, localtime); | ||||
|     text = fmt::format(locale_, fmt::runtime(format_), localtime); | ||||
|   } else { | ||||
|     text = fmt::format(format_, wtime); | ||||
|     text = fmt::format(locale_, fmt::runtime(format_), ztime); | ||||
|   } | ||||
|   label_.set_markup(text); | ||||
|  | ||||
| @@ -142,13 +190,13 @@ auto waybar::modules::Clock::update() -> void { | ||||
|       std::string calendar_lines{""}; | ||||
|       std::string timezoned_time_lines{""}; | ||||
|       if (is_calendar_in_tooltip_) { | ||||
|         calendar_lines = calendar_text(shifted_wtime); | ||||
|         calendar_lines = get_calendar(ztime, shifted_ztime); | ||||
|       } | ||||
|       if (is_timezoned_list_in_tooltip_) { | ||||
|         timezoned_time_lines = timezones_text(&now); | ||||
|       } | ||||
|       auto tooltip_format = config_["tooltip-format"].asString(); | ||||
|       text = fmt::format(tooltip_format, shifted_wtime, | ||||
|       text = fmt::format(locale_, fmt::runtime(tooltip_format), shifted_ztime, | ||||
|                          fmt::arg(kCalendarPlaceholder.c_str(), calendar_lines), | ||||
|                          fmt::arg(KTimezonedTimeListPlaceholder.c_str(), timezoned_time_lines)); | ||||
|       label_.set_tooltip_markup(text); | ||||
| @@ -159,6 +207,21 @@ auto waybar::modules::Clock::update() -> void { | ||||
|   ALabel::update(); | ||||
| } | ||||
|  | ||||
| bool waybar::modules::Clock::handleToggle(GdkEventButton* const& e) { | ||||
|   const std::map<std::pair<uint, GdkEventType>, void (waybar::modules::Clock::*)()>::const_iterator& | ||||
|       rec{eventMap_.find(std::pair(e->button, e->type))}; | ||||
|  | ||||
|   const auto callMethod{(rec != eventMap_.cend()) ? rec->second : nullptr}; | ||||
|  | ||||
|   if (callMethod) { | ||||
|     (this->*callMethod)(); | ||||
|   } else | ||||
|     return AModule::handleToggle(e); | ||||
|  | ||||
|   update(); | ||||
|   return true; | ||||
| } | ||||
|  | ||||
| bool waybar::modules::Clock::handleScroll(GdkEventScroll* e) { | ||||
|   // defer to user commands if set | ||||
|   if (config_["on-scroll-up"].isString() || config_["on-scroll-down"].isString()) { | ||||
| @@ -168,11 +231,11 @@ bool waybar::modules::Clock::handleScroll(GdkEventScroll* e) { | ||||
|   auto dir = AModule::getScrollDir(e); | ||||
|  | ||||
|   // Shift calendar date | ||||
|   if (calendar_shift_init_.count() != 0) { | ||||
|   if (cldShift_.count() != 0) { | ||||
|     if (dir == SCROLL_DIR::UP) | ||||
|       calendar_shift_ += calendar_shift_init_; | ||||
|       cldCurrShift_ += ((cldMode_ == CldMode::YEAR) ? 12 : 1) * cldShift_; | ||||
|     else | ||||
|       calendar_shift_ -= calendar_shift_init_; | ||||
|       cldCurrShift_ -= ((cldMode_ == CldMode::YEAR) ? 12 : 1) * cldShift_; | ||||
|   } else { | ||||
|     // Change time zone | ||||
|     if (dir != SCROLL_DIR::UP && dir != SCROLL_DIR::DOWN) { | ||||
| @@ -196,126 +259,212 @@ bool waybar::modules::Clock::handleScroll(GdkEventScroll* e) { | ||||
|   return true; | ||||
| } | ||||
|  | ||||
| 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 (calendar_cached_ymd_ == ymd) { | ||||
|     return calendar_cached_text_; | ||||
|   } | ||||
|  | ||||
|   const auto curr_day{(calendar_shift_init_.count() != 0 && calendar_shift_.count() != 0) | ||||
|                           ? date::day{0} | ||||
|                           : ymd.day()}; | ||||
|   const date::year_month ym{ymd.year(), ymd.month()}; | ||||
|   const auto first_dow = first_day_of_week(); | ||||
|  | ||||
|   std::stringstream os; | ||||
|  | ||||
|   enum class WeeksSide { | ||||
|     LEFT, | ||||
|     RIGHT, | ||||
|     HIDDEN, | ||||
|   }; | ||||
|   WeeksSide weeks_pos = WeeksSide::HIDDEN; | ||||
|  | ||||
|   if (config_["calendar-weeks-pos"].isString()) { | ||||
|     if (config_["calendar-weeks-pos"].asString() == "left") { | ||||
|       weeks_pos = WeeksSide::LEFT; | ||||
|       // Add paddings before the header | ||||
|       os << std::string(3 + fmt_weeks_left_pad_, ' '); | ||||
|     } else if (config_["calendar-weeks-pos"].asString() == "right") { | ||||
|       weeks_pos = WeeksSide::RIGHT; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   weekdays_header(first_dow, os); | ||||
|  | ||||
|   // First week day prefixed with spaces if needed. | ||||
|   date::sys_days print_wd{ym / 1}; | ||||
|   auto wd{date::weekday{print_wd}}; | ||||
|   auto empty_days = (wd - first_dow).count(); | ||||
|  | ||||
|   /* Print weeknumber on the left for the first row*/ | ||||
|   if (weeks_pos == WeeksSide::LEFT) { | ||||
|     os << fmt::format(fmt_str_weeks_, print_wd) << ' '; | ||||
|   } | ||||
|  | ||||
|   if (empty_days > 0) { | ||||
|     os << std::string(empty_days * 3 - 1, ' '); | ||||
|   } | ||||
|  | ||||
|   const 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) { | ||||
|       if (weeks_pos == WeeksSide::RIGHT) { | ||||
|         os << ' ' << fmt::format(fmt_str_weeks_, print_wd); | ||||
|       } | ||||
|  | ||||
|       os << '\n'; | ||||
|  | ||||
|       print_wd = (ym / d); | ||||
|  | ||||
|       if (weeks_pos == WeeksSide::LEFT) { | ||||
|         os << fmt::format(fmt_str_weeks_, print_wd) << ' '; | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     if (d == curr_day) { | ||||
|       if (config_["today-format"].isString()) { | ||||
|         auto today_format = config_["today-format"].asString(); | ||||
|         os << fmt::format(today_format, date::format("%e", d)); | ||||
|       } else { | ||||
|         os << "<b><u>" << date::format("%e", d) << "</u></b>"; | ||||
|       } | ||||
|     } else { | ||||
|       os << fmt::format(fmt_str_calendar_, date::format("%e", d)); | ||||
|     } | ||||
|     /*Print weeks on the right when the endings with spaces*/ | ||||
|     if (weeks_pos == WeeksSide::RIGHT && d == last_day) { | ||||
|       empty_days = 6 - (wd.c_encoding() - first_dow.c_encoding()); | ||||
|       if (empty_days > 0 && empty_days < 7) { | ||||
|         os << std::string(empty_days * 3, ' '); | ||||
|       } | ||||
|  | ||||
|       os << ' ' << fmt::format(fmt_str_weeks_, print_wd); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   auto result = os.str(); | ||||
|   calendar_cached_ymd_ = ymd; | ||||
|   calendar_cached_text_ = result; | ||||
|   return result; | ||||
| // The number of weeks in calendar month layout plus 1 more for calendar titles | ||||
| unsigned cldRowsInMonth(date::year_month const ym, date::weekday const firstdow) { | ||||
|   using namespace date; | ||||
|   return static_cast<unsigned>( | ||||
|              ceil<weeks>((weekday{ym / 1} - firstdow) + ((ym / last).day() - day{0})).count()) + | ||||
|          2; | ||||
| } | ||||
|  | ||||
| auto waybar::modules::Clock::weekdays_header(const date::weekday& first_week_day, std::ostream& os) | ||||
|     -> void { | ||||
|   std::stringstream res; | ||||
|   auto wd = first_week_day; | ||||
|   do { | ||||
|     if (wd != first_week_day) { | ||||
|       res << ' '; | ||||
|     } | ||||
|     Glib::ustring wd_ustring(date::format(locale_, "%a", wd)); | ||||
|     auto clen = ustring_clen(wd_ustring); | ||||
|     auto wd_len = wd_ustring.length(); | ||||
|     while (clen > 2) { | ||||
|       wd_ustring = wd_ustring.substr(0, wd_len - 1); | ||||
|       wd_len--; | ||||
|       clen = ustring_clen(wd_ustring); | ||||
|     } | ||||
|     const std::string pad(2 - clen, ' '); | ||||
|     res << pad << wd_ustring; | ||||
|   } while (++wd != first_week_day); | ||||
|   res << '\n'; | ||||
| auto cldGetWeekForLine(date::year_month const ym, date::weekday const firstdow, unsigned const line) | ||||
|     -> const date::year_month_weekday { | ||||
|   unsigned index = line - 2; | ||||
|   auto sd = date::sys_days{ym / 1}; | ||||
|   if (date::weekday{sd} == firstdow) ++index; | ||||
|   auto ymdw = ym / firstdow[index]; | ||||
|   return ymdw; | ||||
| } | ||||
|  | ||||
|   if (config_["format-calendar-weekdays"].isString()) { | ||||
|     os << fmt::format(config_["format-calendar-weekdays"].asString(), res.str()); | ||||
|   } else | ||||
|     os << res.str(); | ||||
| auto getCalendarLine(date::year_month_day const currDate, date::year_month const ym, | ||||
|                      unsigned const line, date::weekday const firstdow, int rowLen, | ||||
|                      const std::locale* const locale_) -> std::string { | ||||
|   using namespace date::literals; | ||||
|   std::ostringstream res; | ||||
|  | ||||
|   switch (line) { | ||||
|     case 0: { | ||||
|       // Output month and year title | ||||
|       Glib::ustring wd_ustring{Glib::ustring::format( | ||||
|           std::left, std::setw(rowLen), date::format(*locale_, "%B %Y", ym), std::right)}; | ||||
|       res << wd_ustring; | ||||
|       break; | ||||
|     } | ||||
|     case 1: { | ||||
|       // Output weekday names title | ||||
|       auto wd{firstdow}; | ||||
|       do { | ||||
|         Glib::ustring wd_ustring{date::format(*locale_, "%a", wd)}; | ||||
|         auto clen{ustring_clen(wd_ustring)}; | ||||
|         auto wd_len{wd_ustring.length()}; | ||||
|         while (clen > 2) { | ||||
|           wd_ustring = wd_ustring.substr(0, wd_len - 1); | ||||
|           --wd_len; | ||||
|           clen = ustring_clen(wd_ustring); | ||||
|         } | ||||
|         const std::string pad(2 - clen, ' '); | ||||
|  | ||||
|         if (wd != firstdow) res << ' '; | ||||
|  | ||||
|         res << pad << wd_ustring; | ||||
|       } while (++wd != firstdow); | ||||
|  | ||||
|       break; | ||||
|     } | ||||
|     case 2: { | ||||
|       // Output first week prefixed with spaces if necessary | ||||
|       auto wd = date::weekday{ym / 1}; | ||||
|       res << std::string(static_cast<unsigned>((wd - firstdow).count()) * 3, ' '); | ||||
|  | ||||
|       if (currDate.year() != ym.year() || currDate.month() != ym.month() || currDate != ym / 1_d) | ||||
|         res << date::format("%e", 1_d); | ||||
|       else | ||||
|         res << "{today}"; | ||||
|  | ||||
|       auto d = 2_d; | ||||
|  | ||||
|       while (++wd != firstdow) { | ||||
|         if (currDate.year() != ym.year() || currDate.month() != ym.month() || currDate != ym / d) | ||||
|           res << date::format(" %e", d); | ||||
|         else | ||||
|           res << " {today}"; | ||||
|  | ||||
|         ++d; | ||||
|       } | ||||
|       break; | ||||
|     } | ||||
|     default: { | ||||
|       // Output a non-first week: | ||||
|       auto ymdw{cldGetWeekForLine(ym, firstdow, line)}; | ||||
|       if (ymdw.ok()) { | ||||
|         auto d = date::year_month_day{ymdw}.day(); | ||||
|         auto const e = (ym / last).day(); | ||||
|         auto wd = firstdow; | ||||
|  | ||||
|         if (currDate.year() != ym.year() || currDate.month() != ym.month() || currDate != ym / d) | ||||
|           res << date::format("%e", d); | ||||
|         else | ||||
|           res << "{today}"; | ||||
|  | ||||
|         while (++wd != firstdow && ++d <= e) { | ||||
|           if (currDate.year() != ym.year() || currDate.month() != ym.month() || currDate != ym / d) | ||||
|             res << date::format(" %e", d); | ||||
|           else | ||||
|             res << " {today}"; | ||||
|         } | ||||
|         // Append row with spaces if the week did not complete | ||||
|         res << std::string(static_cast<unsigned>((firstdow - wd).count()) * 3, ' '); | ||||
|       } else  // Otherwise not a valid week, output a blank row | ||||
|         res << std::string(rowLen, ' '); | ||||
|  | ||||
|       break; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   return res.str(); | ||||
| } | ||||
|  | ||||
| auto waybar::modules::Clock::get_calendar(const date::zoned_seconds& now, | ||||
|                                           const date::zoned_seconds& wtime) -> std::string { | ||||
|   auto daypoint = date::floor<date::days>(wtime.get_local_time()); | ||||
|   const auto ymd{date::year_month_day{daypoint}}; | ||||
|   const auto ym{ymd.year() / ymd.month()}; | ||||
|   const auto y{ymd.year()}; | ||||
|   const auto firstdow = first_day_of_week(); | ||||
|   const auto maxRows{12 / cldMonCols_}; | ||||
|   std::ostringstream os; | ||||
|   std::ostringstream tmp; | ||||
|   // get currdate | ||||
|   daypoint = date::floor<date::days>(now.get_local_time()); | ||||
|   const auto currDate{date::year_month_day{daypoint}}; | ||||
|  | ||||
|   if (cldMode_ == CldMode::YEAR) { | ||||
|     if (y / date::month{1} / 1 == cldYearShift_) | ||||
|       return cldYearCached_; | ||||
|     else | ||||
|       cldYearShift_ = y / date::month{1} / 1; | ||||
|   } | ||||
|   if (cldMode_ == CldMode::MONTH) { | ||||
|     if (ym == cldMonShift_) | ||||
|       return cldMonCached_; | ||||
|     else | ||||
|       cldMonShift_ = ym; | ||||
|   } | ||||
|  | ||||
|   // Compute number of lines needed for each calendar month | ||||
|   unsigned ml[12]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; | ||||
|  | ||||
|   for (auto& m : ml) { | ||||
|     if (cldMode_ == CldMode::YEAR || m == static_cast<unsigned>(ymd.month())) | ||||
|       m = cldRowsInMonth(y / date::month{m}, firstdow); | ||||
|     else | ||||
|       m = 0u; | ||||
|   } | ||||
|   for (auto row{0u}; row < maxRows; ++row) { | ||||
|     const auto lines = *std::max_element(std::begin(ml) + (row * cldMonCols_), | ||||
|                                          std::begin(ml) + ((row + 1) * cldMonCols_)); | ||||
|     for (auto line{0u}; line < lines; ++line) { | ||||
|       for (auto col{0u}; col < cldMonCols_; ++col) { | ||||
|         const auto mon{date::month{row * cldMonCols_ + col + 1}}; | ||||
|         if (cldMode_ == CldMode::YEAR || y / mon == ym) { | ||||
|           date::year_month ymTmp{y / mon}; | ||||
|           if (col != 0 && cldMode_ == CldMode::YEAR) os << "   "; | ||||
|  | ||||
|           // Week numbers on the left | ||||
|           if (cldWPos_ == WeeksSide::LEFT && line > 0) { | ||||
|             if (line == 1 && cldWnLen_ > 0) os << std::string(cldWnLen_, ' '); | ||||
|  | ||||
|             if (line > 1 && line < ml[static_cast<unsigned>(ymTmp.month()) - 1u]) | ||||
|               os << fmt::format(fmt::runtime(fmtMap_[4]), | ||||
|                                 (line == 2) | ||||
|                                     ? date::sys_days{ymTmp / 1} | ||||
|                                     : date::sys_days{cldGetWeekForLine(ymTmp, firstdow, line)}) | ||||
|                  << ' '; | ||||
|           } | ||||
|  | ||||
|           os << getCalendarLine(currDate, ymTmp, line, firstdow, cldMonColLen_, &locale_); | ||||
|  | ||||
|           // Week numbers on the right | ||||
|           if (cldWPos_ == WeeksSide ::RIGHT && line > 0) { | ||||
|             if (line == 1 && cldWnLen_ > 0) os << std::string(cldWnLen_, ' '); | ||||
|  | ||||
|             if (line > 1 && line < ml[static_cast<unsigned>(ymTmp.month()) - 1u]) | ||||
|               os << ' ' | ||||
|                  << fmt::format(fmt::runtime(fmtMap_[4]), | ||||
|                                 (line == 2) | ||||
|                                     ? date::sys_days{ymTmp / 1} | ||||
|                                     : date::sys_days{cldGetWeekForLine(ymTmp, firstdow, line)}); | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|  | ||||
|       // Apply user formats to calendar | ||||
|       if (line < 2) | ||||
|         tmp << fmt::format(fmt::runtime(fmtMap_[line]), os.str()); | ||||
|       else | ||||
|         tmp << os.str(); | ||||
|       // Clear ostringstream | ||||
|       std::ostringstream().swap(os); | ||||
|       if (line + 1u != lines || (row + 1u != maxRows && cldMode_ == CldMode::YEAR)) tmp << '\n'; | ||||
|     } | ||||
|     if (row + 1u != maxRows && cldMode_ == CldMode::YEAR) tmp << '\n'; | ||||
|   } | ||||
|  | ||||
|   os << fmt::format(  // Apply days format | ||||
|       fmt::runtime(fmt::format(fmt::runtime(fmtMap_[2]), tmp.str())), | ||||
|       // Apply today format | ||||
|       fmt::arg("today", fmt::format(fmt::runtime(fmtMap_[3]), date::format("%e", ymd.day())))); | ||||
|  | ||||
|   if (cldMode_ == CldMode::YEAR) | ||||
|     cldYearCached_ = os.str(); | ||||
|   else | ||||
|     cldMonCached_ = os.str(); | ||||
|  | ||||
|   return os.str(); | ||||
| } | ||||
|  | ||||
| void waybar::modules::Clock::cldModeSwitch() { | ||||
|   cldMode_ = (cldMode_ == CldMode::YEAR) ? CldMode::MONTH : CldMode::YEAR; | ||||
| } | ||||
|  | ||||
| auto waybar::modules::Clock::timezones_text(std::chrono::system_clock::time_point* now) | ||||
| @@ -324,7 +473,6 @@ auto waybar::modules::Clock::timezones_text(std::chrono::system_clock::time_poin | ||||
|     return ""; | ||||
|   } | ||||
|   std::stringstream os; | ||||
|   waybar_time wtime; | ||||
|   for (size_t time_zone_idx = 0; time_zone_idx < time_zones_.size(); ++time_zone_idx) { | ||||
|     if (static_cast<int>(time_zone_idx) == current_time_zone_idx_) { | ||||
|       continue; | ||||
| @@ -333,8 +481,8 @@ auto waybar::modules::Clock::timezones_text(std::chrono::system_clock::time_poin | ||||
|     if (!timezone) { | ||||
|       timezone = date::current_zone(); | ||||
|     } | ||||
|     wtime = {locale_, date::make_zoned(timezone, date::floor<std::chrono::seconds>(*now))}; | ||||
|     os << fmt::format(format_, wtime) << '\n'; | ||||
|     auto ztime = date::zoned_time{timezone, date::floor<std::chrono::seconds>(*now)}; | ||||
|     os << fmt::format(locale_, fmt::runtime(format_), ztime) << '\n'; | ||||
|   } | ||||
|   return os.str(); | ||||
| } | ||||
|   | ||||
| @@ -126,7 +126,7 @@ auto waybar::modules::Custom::update() -> void { | ||||
|     } else { | ||||
|       parseOutputRaw(); | ||||
|     } | ||||
|     auto str = fmt::format(format_, text_, fmt::arg("alt", alt_), | ||||
|     auto str = fmt::format(fmt::runtime(format_), text_, fmt::arg("alt", alt_), | ||||
|                            fmt::arg("icon", getIcon(percentage_, alt_)), | ||||
|                            fmt::arg("percentage", percentage_)); | ||||
|     if (str.empty()) { | ||||
| @@ -209,8 +209,8 @@ void waybar::modules::Custom::parseOutputJson() { | ||||
|         class_.push_back(c.asString()); | ||||
|       } | ||||
|     } | ||||
|     if (!parsed["percentage"].asString().empty() && parsed["percentage"].isUInt()) { | ||||
|       percentage_ = parsed["percentage"].asUInt(); | ||||
|     if (!parsed["percentage"].asString().empty() && parsed["percentage"].isNumeric()) { | ||||
|       percentage_ = (int)lround(parsed["percentage"].asFloat()); | ||||
|     } else { | ||||
|       percentage_ = 0; | ||||
|     } | ||||
|   | ||||
| @@ -58,11 +58,11 @@ auto waybar::modules::Disk::update() -> void { | ||||
|     event_box_.hide(); | ||||
|   } else { | ||||
|     event_box_.show(); | ||||
|     label_.set_markup( | ||||
|         fmt::format(format, stats.f_bavail * 100 / stats.f_blocks, fmt::arg("free", free), | ||||
|                     fmt::arg("percentage_free", stats.f_bavail * 100 / stats.f_blocks), | ||||
|                     fmt::arg("used", used), fmt::arg("percentage_used", percentage_used), | ||||
|                     fmt::arg("total", total), fmt::arg("path", path_))); | ||||
|     label_.set_markup(fmt::format( | ||||
|         fmt::runtime(format), stats.f_bavail * 100 / stats.f_blocks, fmt::arg("free", free), | ||||
|         fmt::arg("percentage_free", stats.f_bavail * 100 / stats.f_blocks), fmt::arg("used", used), | ||||
|         fmt::arg("percentage_used", percentage_used), fmt::arg("total", total), | ||||
|         fmt::arg("path", path_))); | ||||
|   } | ||||
|  | ||||
|   if (tooltipEnabled()) { | ||||
| @@ -70,11 +70,11 @@ auto waybar::modules::Disk::update() -> void { | ||||
|     if (config_["tooltip-format"].isString()) { | ||||
|       tooltip_format = config_["tooltip-format"].asString(); | ||||
|     } | ||||
|     label_.set_tooltip_text( | ||||
|         fmt::format(tooltip_format, stats.f_bavail * 100 / stats.f_blocks, fmt::arg("free", free), | ||||
|                     fmt::arg("percentage_free", stats.f_bavail * 100 / stats.f_blocks), | ||||
|                     fmt::arg("used", used), fmt::arg("percentage_used", percentage_used), | ||||
|                     fmt::arg("total", total), fmt::arg("path", path_))); | ||||
|     label_.set_tooltip_text(fmt::format( | ||||
|         fmt::runtime(tooltip_format), stats.f_bavail * 100 / stats.f_blocks, fmt::arg("free", free), | ||||
|         fmt::arg("percentage_free", stats.f_bavail * 100 / stats.f_blocks), fmt::arg("used", used), | ||||
|         fmt::arg("percentage_used", percentage_used), fmt::arg("total", total), | ||||
|         fmt::arg("path", path_))); | ||||
|   } | ||||
|   // Call parent update | ||||
|   ALabel::update(); | ||||
|   | ||||
| @@ -213,14 +213,14 @@ auto Gamemode::update() -> void { | ||||
|  | ||||
|   // Tooltip | ||||
|   if (tooltip) { | ||||
|     std::string text = fmt::format(tooltip_format, fmt::arg("count", gameCount)); | ||||
|     std::string text = fmt::format(fmt::runtime(tooltip_format), fmt::arg("count", gameCount)); | ||||
|     box_.set_tooltip_text(text); | ||||
|   } | ||||
|  | ||||
|   // Label format | ||||
|   std::string str = | ||||
|       fmt::format(showAltText ? format_alt : format, fmt::arg("glyph", useIcon ? "" : glyph), | ||||
|                   fmt::arg("count", gameCount > 0 ? std::to_string(gameCount) : "")); | ||||
|   std::string str = fmt::format(fmt::runtime(showAltText ? format_alt : format), | ||||
|                                 fmt::arg("glyph", useIcon ? "" : glyph), | ||||
|                                 fmt::arg("count", gameCount > 0 ? std::to_string(gameCount) : "")); | ||||
|   label_.set_markup(str); | ||||
|  | ||||
|   if (useIcon) { | ||||
|   | ||||
| @@ -55,17 +55,17 @@ void Language::onEvent(const std::string& ev) { | ||||
|   if (config_.isMember("keyboard-name") && kbName != config_["keyboard-name"].asString()) | ||||
|     return;  // ignore | ||||
|  | ||||
|   layoutName = waybar::util::sanitize_string(layoutName); | ||||
|  | ||||
|   const auto briefName = getShortFrom(layoutName); | ||||
|  | ||||
|   if (config_.isMember("format-" + briefName)) { | ||||
|     const auto propName = "format-" + briefName; | ||||
|     layoutName = fmt::format(format_, config_[propName].asString()); | ||||
|     layoutName = fmt::format(fmt::runtime(format_), config_[propName].asString()); | ||||
|   } else { | ||||
|     layoutName = fmt::format(format_, layoutName); | ||||
|     layoutName = fmt::format(fmt::runtime(format_), layoutName); | ||||
|   } | ||||
|  | ||||
|   layoutName = waybar::util::sanitize_string(layoutName); | ||||
|  | ||||
|   if (layoutName == layoutName_) return; | ||||
|  | ||||
|   layoutName_ = layoutName; | ||||
| @@ -87,18 +87,18 @@ void Language::initLanguage() { | ||||
|     searcher = searcher.substr(searcher.find("keymap:") + 8); | ||||
|     searcher = searcher.substr(0, searcher.find_first_of("\n\t")); | ||||
|  | ||||
|     searcher = waybar::util::sanitize_string(searcher); | ||||
|  | ||||
|     auto layoutName = std::string{}; | ||||
|     const auto briefName = getShortFrom(searcher); | ||||
|  | ||||
|     if (config_.isMember("format-" + briefName)) { | ||||
|       const auto propName = "format-" + briefName; | ||||
|       layoutName = fmt::format(format_, config_[propName].asString()); | ||||
|       layoutName = fmt::format(fmt::runtime(format_), config_[propName].asString()); | ||||
|     } else { | ||||
|       layoutName = fmt::format(format_, searcher); | ||||
|       layoutName = fmt::format(fmt::runtime(format_), searcher); | ||||
|     } | ||||
|  | ||||
|     layoutName = waybar::util::sanitize_string(layoutName); | ||||
|  | ||||
|     layoutName_ = layoutName; | ||||
|  | ||||
|     spdlog::debug("hyprland language initLanguage found {}", layoutName_); | ||||
|   | ||||
| @@ -19,6 +19,7 @@ Submap::Submap(const std::string& id, const Bar& bar, const Json::Value& config) | ||||
|  | ||||
|   // register for hyprland ipc | ||||
|   gIPC->registerForIPC("submap", this); | ||||
|   dp.emit(); | ||||
| } | ||||
|  | ||||
| Submap::~Submap() { | ||||
| @@ -33,7 +34,7 @@ auto Submap::update() -> void { | ||||
|   if (submap_.empty()) { | ||||
|     event_box_.hide(); | ||||
|   } else { | ||||
|     label_.set_markup(fmt::format(format_, submap_)); | ||||
|     label_.set_markup(fmt::format(fmt::runtime(format_), submap_)); | ||||
|     if (tooltipEnabled()) { | ||||
|       label_.set_tooltip_text(submap_); | ||||
|     } | ||||
|   | ||||
| @@ -40,8 +40,8 @@ auto Window::update() -> void { | ||||
|  | ||||
|   if (!format_.empty()) { | ||||
|     label_.show(); | ||||
|     label_.set_markup( | ||||
|         fmt::format(format_, waybar::util::rewriteTitle(lastView, config_["rewrite"]))); | ||||
|     label_.set_markup(fmt::format(fmt::runtime(format_), | ||||
|                                   waybar::util::rewriteTitle(lastView, config_["rewrite"]))); | ||||
|   } else { | ||||
|     label_.hide(); | ||||
|   } | ||||
|   | ||||
| @@ -63,21 +63,15 @@ auto waybar::modules::IdleInhibitor::update() -> void { | ||||
|   } | ||||
|  | ||||
|   std::string status_text = status ? "activated" : "deactivated"; | ||||
|   label_.set_markup(fmt::format(format_, fmt::arg("status", status_text), | ||||
|   label_.set_markup(fmt::format(fmt::runtime(format_), fmt::arg("status", status_text), | ||||
|                                 fmt::arg("icon", getIcon(0, status_text)))); | ||||
|   label_.get_style_context()->add_class(status_text); | ||||
|   if (tooltipEnabled()) { | ||||
|     label_.set_tooltip_markup( | ||||
|         status ? fmt::format(config_["tooltip-format-activated"].isString() | ||||
|                                  ? config_["tooltip-format-activated"].asString() | ||||
|                                  : "{status}", | ||||
|                              fmt::arg("status", status_text), | ||||
|                              fmt::arg("icon", getIcon(0, status_text))) | ||||
|                : fmt::format(config_["tooltip-format-deactivated"].isString() | ||||
|                                  ? config_["tooltip-format-deactivated"].asString() | ||||
|                                  : "{status}", | ||||
|                              fmt::arg("status", status_text), | ||||
|                              fmt::arg("icon", getIcon(0, status_text)))); | ||||
|     auto config = config_[status ? "tooltip-format-activated" : "tooltip-format-deactivated"]; | ||||
|     auto tooltip_format = config.isString() ? config.asString() : "{status}"; | ||||
|     label_.set_tooltip_markup(fmt::format(fmt::runtime(tooltip_format), | ||||
|                                           fmt::arg("status", status_text), | ||||
|                                           fmt::arg("icon", getIcon(0, status_text)))); | ||||
|   } | ||||
|   // Call parent update | ||||
|   ALabel::update(); | ||||
|   | ||||
| @@ -118,7 +118,7 @@ auto Inhibitor::update() -> void { | ||||
|   std::string status_text = activated() ? "activated" : "deactivated"; | ||||
|  | ||||
|   label_.get_style_context()->remove_class(activated() ? "deactivated" : "activated"); | ||||
|   label_.set_markup(fmt::format(format_, fmt::arg("status", status_text), | ||||
|   label_.set_markup(fmt::format(fmt::runtime(format_), fmt::arg("status", status_text), | ||||
|                                 fmt::arg("icon", getIcon(0, status_text)))); | ||||
|   label_.get_style_context()->add_class(status_text); | ||||
|  | ||||
|   | ||||
| @@ -72,7 +72,7 @@ auto JACK::update() -> void { | ||||
|   } else | ||||
|     format = "{load}%"; | ||||
|  | ||||
|   label_.set_markup(fmt::format(format, fmt::arg("load", std::round(load_)), | ||||
|   label_.set_markup(fmt::format(fmt::runtime(format), fmt::arg("load", std::round(load_)), | ||||
|                                 fmt::arg("bufsize", bufsize_), fmt::arg("samplerate", samplerate_), | ||||
|                                 fmt::arg("latency", fmt::format("{:.2f}", latency)), | ||||
|                                 fmt::arg("xruns", xruns_))); | ||||
| @@ -81,9 +81,9 @@ auto JACK::update() -> void { | ||||
|     std::string tooltip_format = "{bufsize}/{samplerate} {latency}ms"; | ||||
|     if (config_["tooltip-format"].isString()) tooltip_format = config_["tooltip-format"].asString(); | ||||
|     label_.set_tooltip_text(fmt::format( | ||||
|         tooltip_format, fmt::arg("load", std::round(load_)), fmt::arg("bufsize", bufsize_), | ||||
|         fmt::arg("samplerate", samplerate_), fmt::arg("latency", fmt::format("{:.2f}", latency)), | ||||
|         fmt::arg("xruns", xruns_))); | ||||
|         fmt::runtime(tooltip_format), fmt::arg("load", std::round(load_)), | ||||
|         fmt::arg("bufsize", bufsize_), fmt::arg("samplerate", samplerate_), | ||||
|         fmt::arg("latency", fmt::format("{:.2f}", latency)), fmt::arg("xruns", xruns_))); | ||||
|   } | ||||
|  | ||||
|   // Call parent update | ||||
|   | ||||
| @@ -278,7 +278,7 @@ auto waybar::modules::KeyboardState::update() -> void { | ||||
|   }; | ||||
|   for (auto& label_state : label_states) { | ||||
|     std::string text; | ||||
|     text = fmt::format(label_state.format, | ||||
|     text = fmt::format(fmt::runtime(label_state.format), | ||||
|                        fmt::arg("icon", label_state.state ? icon_locked_ : icon_unlocked_), | ||||
|                        fmt::arg("name", label_state.name)); | ||||
|     label_state.label.set_markup(text); | ||||
|   | ||||
| @@ -56,7 +56,8 @@ auto waybar::modules::Memory::update() -> void { | ||||
|       event_box_.show(); | ||||
|       auto icons = std::vector<std::string>{state}; | ||||
|       label_.set_markup(fmt::format( | ||||
|           format, used_ram_percentage, fmt::arg("icon", getIcon(used_ram_percentage, icons)), | ||||
|           fmt::runtime(format), used_ram_percentage, | ||||
|           fmt::arg("icon", getIcon(used_ram_percentage, icons)), | ||||
|           fmt::arg("total", total_ram_gigabytes), fmt::arg("swapTotal", total_swap_gigabytes), | ||||
|           fmt::arg("percentage", used_ram_percentage), | ||||
|           fmt::arg("swapPercentage", used_swap_percentage), fmt::arg("used", used_ram_gigabytes), | ||||
| @@ -68,8 +69,8 @@ auto waybar::modules::Memory::update() -> void { | ||||
|       if (config_["tooltip-format"].isString()) { | ||||
|         auto tooltip_format = config_["tooltip-format"].asString(); | ||||
|         label_.set_tooltip_text(fmt::format( | ||||
|             tooltip_format, used_ram_percentage, fmt::arg("total", total_ram_gigabytes), | ||||
|             fmt::arg("swapTotal", total_swap_gigabytes), | ||||
|             fmt::runtime(tooltip_format), used_ram_percentage, | ||||
|             fmt::arg("total", total_ram_gigabytes), fmt::arg("swapTotal", total_swap_gigabytes), | ||||
|             fmt::arg("percentage", used_ram_percentage), | ||||
|             fmt::arg("swapPercentage", used_swap_percentage), fmt::arg("used", used_ram_gigabytes), | ||||
|             fmt::arg("swapUsed", used_swap_gigabytes), fmt::arg("avail", available_ram_gigabytes), | ||||
|   | ||||
| @@ -174,14 +174,14 @@ void waybar::modules::MPD::setLabel() { | ||||
|  | ||||
|   try { | ||||
|     auto text = fmt::format( | ||||
|         format, fmt::arg("artist", artist.raw()), fmt::arg("albumArtist", album_artist.raw()), | ||||
|         fmt::arg("album", album.raw()), fmt::arg("title", title.raw()), fmt::arg("date", date), | ||||
|         fmt::arg("volume", volume), fmt::arg("elapsedTime", elapsedTime), | ||||
|         fmt::arg("totalTime", totalTime), fmt::arg("songPosition", song_pos), | ||||
|         fmt::arg("queueLength", queue_length), fmt::arg("stateIcon", stateIcon), | ||||
|         fmt::arg("consumeIcon", consumeIcon), fmt::arg("randomIcon", randomIcon), | ||||
|         fmt::arg("repeatIcon", repeatIcon), fmt::arg("singleIcon", singleIcon), | ||||
|         fmt::arg("filename", filename)); | ||||
|         fmt::runtime(format), fmt::arg("artist", artist.raw()), | ||||
|         fmt::arg("albumArtist", album_artist.raw()), fmt::arg("album", album.raw()), | ||||
|         fmt::arg("title", title.raw()), fmt::arg("date", date), fmt::arg("volume", volume), | ||||
|         fmt::arg("elapsedTime", elapsedTime), fmt::arg("totalTime", totalTime), | ||||
|         fmt::arg("songPosition", song_pos), fmt::arg("queueLength", queue_length), | ||||
|         fmt::arg("stateIcon", stateIcon), fmt::arg("consumeIcon", consumeIcon), | ||||
|         fmt::arg("randomIcon", randomIcon), fmt::arg("repeatIcon", repeatIcon), | ||||
|         fmt::arg("singleIcon", singleIcon), fmt::arg("filename", filename)); | ||||
|     if (text.empty()) { | ||||
|       label_.hide(); | ||||
|     } else { | ||||
| @@ -198,7 +198,7 @@ void waybar::modules::MPD::setLabel() { | ||||
|                                                           : "MPD (connected)"; | ||||
|     try { | ||||
|       auto tooltip_text = | ||||
|           fmt::format(tooltip_format, fmt::arg("artist", artist.raw()), | ||||
|           fmt::format(fmt::runtime(tooltip_format), fmt::arg("artist", artist.raw()), | ||||
|                       fmt::arg("albumArtist", album_artist.raw()), fmt::arg("album", album.raw()), | ||||
|                       fmt::arg("title", title.raw()), fmt::arg("date", date), | ||||
|                       fmt::arg("volume", volume), fmt::arg("elapsedTime", elapsedTime), | ||||
|   | ||||
| @@ -378,10 +378,10 @@ auto Mpris::update() -> void { | ||||
|       break; | ||||
|   } | ||||
|   auto label_format = | ||||
|       fmt::format(formatstr, fmt::arg("player", info.name), fmt::arg("status", info.status_string), | ||||
|                   fmt::arg("artist", *info.artist), fmt::arg("title", *info.title), | ||||
|                   fmt::arg("album", *info.album), fmt::arg("length", *info.length), | ||||
|                   fmt::arg("dynamic", dynamic.str()), | ||||
|       fmt::format(fmt::runtime(formatstr), fmt::arg("player", info.name), | ||||
|                   fmt::arg("status", info.status_string), fmt::arg("artist", *info.artist), | ||||
|                   fmt::arg("title", *info.title), fmt::arg("album", *info.album), | ||||
|                   fmt::arg("length", *info.length), fmt::arg("dynamic", dynamic.str()), | ||||
|                   fmt::arg("player_icon", getIcon(config_["player-icons"], info.name)), | ||||
|                   fmt::arg("status_icon", getIcon(config_["status-icons"], info.status_string))); | ||||
|   label_.set_markup(label_format); | ||||
|   | ||||
| @@ -331,7 +331,7 @@ auto waybar::modules::Network::update() -> void { | ||||
|   getState(signal_strength_); | ||||
|  | ||||
|   auto text = fmt::format( | ||||
|       format_, fmt::arg("essid", essid_), fmt::arg("signaldBm", signal_strength_dbm_), | ||||
|       fmt::runtime(format_), fmt::arg("essid", essid_), fmt::arg("signaldBm", signal_strength_dbm_), | ||||
|       fmt::arg("signalStrength", signal_strength_), | ||||
|       fmt::arg("signalStrengthApp", signal_strength_app_), fmt::arg("ifname", ifname_), | ||||
|       fmt::arg("netmask", netmask_), fmt::arg("ipaddr", ipaddr_), fmt::arg("gwaddr", gwaddr_), | ||||
| @@ -363,8 +363,8 @@ auto waybar::modules::Network::update() -> void { | ||||
|     } | ||||
|     if (!tooltip_format.empty()) { | ||||
|       auto tooltip_text = fmt::format( | ||||
|           tooltip_format, fmt::arg("essid", essid_), fmt::arg("signaldBm", signal_strength_dbm_), | ||||
|           fmt::arg("signalStrength", signal_strength_), | ||||
|           fmt::runtime(tooltip_format), fmt::arg("essid", essid_), | ||||
|           fmt::arg("signaldBm", signal_strength_dbm_), fmt::arg("signalStrength", signal_strength_), | ||||
|           fmt::arg("signalStrengthApp", signal_strength_app_), fmt::arg("ifname", ifname_), | ||||
|           fmt::arg("netmask", netmask_), fmt::arg("ipaddr", ipaddr_), fmt::arg("gwaddr", gwaddr_), | ||||
|           fmt::arg("cidr", cidr_), fmt::arg("frequency", fmt::format("{:.1f}", frequency_)), | ||||
|   | ||||
| @@ -294,9 +294,9 @@ auto waybar::modules::Pulseaudio::update() -> void { | ||||
|       format_source = config_["format-source"].asString(); | ||||
|     } | ||||
|   } | ||||
|   format_source = fmt::format(format_source, fmt::arg("volume", source_volume_)); | ||||
|   format_source = fmt::format(fmt::runtime(format_source), fmt::arg("volume", source_volume_)); | ||||
|   auto text = fmt::format( | ||||
|       format, fmt::arg("desc", desc_), fmt::arg("volume", volume_), | ||||
|       fmt::runtime(format), fmt::arg("desc", desc_), fmt::arg("volume", volume_), | ||||
|       fmt::arg("format_source", format_source), fmt::arg("source_volume", source_volume_), | ||||
|       fmt::arg("source_desc", source_desc_), fmt::arg("icon", getIcon(volume_, getPulseIcon()))); | ||||
|   if (text.empty()) { | ||||
| @@ -313,7 +313,7 @@ auto waybar::modules::Pulseaudio::update() -> void { | ||||
|     } | ||||
|     if (!tooltip_format.empty()) { | ||||
|       label_.set_tooltip_text(fmt::format( | ||||
|           tooltip_format, fmt::arg("desc", desc_), fmt::arg("volume", volume_), | ||||
|           fmt::runtime(tooltip_format), fmt::arg("desc", desc_), fmt::arg("volume", volume_), | ||||
|           fmt::arg("format_source", format_source), fmt::arg("source_volume", source_volume_), | ||||
|           fmt::arg("source_desc", source_desc_), | ||||
|           fmt::arg("icon", getIcon(volume_, getPulseIcon())))); | ||||
|   | ||||
| @@ -103,7 +103,7 @@ void Mode::handle_mode(const char *mode) { | ||||
|     } | ||||
|  | ||||
|     label_.get_style_context()->add_class(mode); | ||||
|     label_.set_markup(fmt::format(format_, Glib::Markup::escape_text(mode).raw())); | ||||
|     label_.set_markup(fmt::format(fmt::runtime(format_), Glib::Markup::escape_text(mode).raw())); | ||||
|     label_.show(); | ||||
|   } | ||||
|  | ||||
|   | ||||
| @@ -106,7 +106,7 @@ void Window::handle_focused_view(const char *title) { | ||||
|     label_.hide();  // hide empty labels or labels with empty format | ||||
|   } else { | ||||
|     label_.show(); | ||||
|     label_.set_markup(fmt::format(format_, Glib::Markup::escape_text(title).raw())); | ||||
|     label_.set_markup(fmt::format(fmt::runtime(format_), Glib::Markup::escape_text(title).raw())); | ||||
|   } | ||||
|  | ||||
|   ALabel::update(); | ||||
|   | ||||
| @@ -110,7 +110,8 @@ auto Sndio::update() -> void { | ||||
|     label_.get_style_context()->remove_class("muted"); | ||||
|   } | ||||
|  | ||||
|   auto text = fmt::format(format, fmt::arg("volume", vol), fmt::arg("raw_value", volume_)); | ||||
|   auto text = | ||||
|       fmt::format(fmt::runtime(format), fmt::arg("volume", vol), fmt::arg("raw_value", volume_)); | ||||
|   if (text.empty()) { | ||||
|     label_.hide(); | ||||
|   } else { | ||||
|   | ||||
| @@ -2,6 +2,8 @@ | ||||
|  | ||||
| #include <fcntl.h> | ||||
|  | ||||
| #include <stdexcept> | ||||
|  | ||||
| namespace waybar::modules::sway { | ||||
|  | ||||
| Ipc::Ipc() { | ||||
|   | ||||
| @@ -96,14 +96,14 @@ void Language::onEvent(const struct Ipc::ipc_response& res) { | ||||
| auto Language::update() -> void { | ||||
|   std::lock_guard<std::mutex> lock(mutex_); | ||||
|   auto display_layout = trim(fmt::format( | ||||
|       format_, fmt::arg("short", layout_.short_name), | ||||
|       fmt::runtime(format_), fmt::arg("short", layout_.short_name), | ||||
|       fmt::arg("shortDescription", layout_.short_description), fmt::arg("long", layout_.full_name), | ||||
|       fmt::arg("variant", layout_.variant), fmt::arg("flag", layout_.country_flag()))); | ||||
|   label_.set_markup(display_layout); | ||||
|   if (tooltipEnabled()) { | ||||
|     if (tooltip_format_ != "") { | ||||
|       auto tooltip_display_layout = trim( | ||||
|           fmt::format(tooltip_format_, fmt::arg("short", layout_.short_name), | ||||
|           fmt::format(fmt::runtime(tooltip_format_), fmt::arg("short", layout_.short_name), | ||||
|                       fmt::arg("shortDescription", layout_.short_description), | ||||
|                       fmt::arg("long", layout_.full_name), fmt::arg("variant", layout_.variant), | ||||
|                       fmt::arg("flag", layout_.country_flag()))); | ||||
|   | ||||
| @@ -42,7 +42,7 @@ auto Mode::update() -> void { | ||||
|   if (mode_.empty()) { | ||||
|     event_box_.hide(); | ||||
|   } else { | ||||
|     label_.set_markup(fmt::format(format_, mode_)); | ||||
|     label_.set_markup(fmt::format(fmt::runtime(format_), mode_)); | ||||
|     if (tooltipEnabled()) { | ||||
|       label_.set_tooltip_text(mode_); | ||||
|     } | ||||
|   | ||||
| @@ -32,7 +32,8 @@ auto Scratchpad::update() -> void { | ||||
|   if (count_ || show_empty_) { | ||||
|     event_box_.show(); | ||||
|     label_.set_markup( | ||||
|         fmt::format(format_, fmt::arg("icon", getIcon(count_, "", config_["format-icons"].size())), | ||||
|         fmt::format(fmt::runtime(format_), | ||||
|                     fmt::arg("icon", getIcon(count_, "", config_["format-icons"].size())), | ||||
|                     fmt::arg("count", count_))); | ||||
|     if (tooltip_enabled_) { | ||||
|       label_.set_tooltip_markup(tooltip_text_); | ||||
| @@ -64,7 +65,7 @@ auto Scratchpad::onCmd(const struct Ipc::ipc_response& res) -> void { | ||||
|     if (tooltip_enabled_) { | ||||
|       tooltip_text_.clear(); | ||||
|       for (const auto& window : tree["nodes"][0]["nodes"][0]["floating_nodes"]) { | ||||
|         tooltip_text_.append(fmt::format(tooltip_format_ + '\n', | ||||
|         tooltip_text_.append(fmt::format(fmt::runtime(tooltip_format_ + '\n'), | ||||
|                                          fmt::arg("app", window["app_id"].asString()), | ||||
|                                          fmt::arg("title", window["name"].asString()))); | ||||
|       } | ||||
|   | ||||
| @@ -204,9 +204,10 @@ auto Window::update() -> void { | ||||
|     old_app_id_ = app_id_; | ||||
|   } | ||||
|  | ||||
|   label_.set_markup(fmt::format( | ||||
|       format_, fmt::arg("title", waybar::util::rewriteTitle(window_, config_["rewrite"])), | ||||
|       fmt::arg("app_id", app_id_), fmt::arg("shell", shell_))); | ||||
|   label_.set_markup( | ||||
|       fmt::format(fmt::runtime(format_), | ||||
|                   fmt::arg("title", waybar::util::rewriteTitle(window_, config_["rewrite"])), | ||||
|                   fmt::arg("app_id", app_id_), fmt::arg("shell", shell_))); | ||||
|   if (tooltipEnabled()) { | ||||
|     label_.set_tooltip_text(window_); | ||||
|   } | ||||
|   | ||||
| @@ -233,7 +233,7 @@ auto Workspaces::update() -> void { | ||||
|     std::string output = (*it)["name"].asString(); | ||||
|     if (config_["format"].isString()) { | ||||
|       auto format = config_["format"].asString(); | ||||
|       output = fmt::format(format, fmt::arg("icon", getIcon(output, *it)), | ||||
|       output = fmt::format(fmt::runtime(format), fmt::arg("icon", getIcon(output, *it)), | ||||
|                            fmt::arg("value", output), fmt::arg("name", trimWorkspaceName(output)), | ||||
|                            fmt::arg("index", (*it)["num"].asString())); | ||||
|     } | ||||
| @@ -259,11 +259,9 @@ Gtk::Button &Workspaces::addButton(const Json::Value &node) { | ||||
|       try { | ||||
|         if (node["target_output"].isString()) { | ||||
|           ipc_.sendCmd(IPC_COMMAND, | ||||
|                        fmt::format(workspace_switch_cmd_ + "; move workspace to output \"{}\"; " + | ||||
|                                        workspace_switch_cmd_, | ||||
|                                    "--no-auto-back-and-forth", node["name"].asString(), | ||||
|                                    node["target_output"].asString(), "--no-auto-back-and-forth", | ||||
|                                    node["name"].asString())); | ||||
|                        fmt::format(persistent_workspace_switch_cmd_, "--no-auto-back-and-forth", | ||||
|                                    node["name"].asString(), node["target_output"].asString(), | ||||
|                                    "--no-auto-back-and-forth", node["name"].asString())); | ||||
|         } else { | ||||
|           ipc_.sendCmd(IPC_COMMAND, fmt::format("workspace {} \"{}\"", | ||||
|                                                 config_["disable-auto-back-and-forth"].asBool() | ||||
|   | ||||
| @@ -55,7 +55,7 @@ auto waybar::modules::Temperature::update() -> void { | ||||
|   } | ||||
|  | ||||
|   auto max_temp = config_["critical-threshold"].isInt() ? config_["critical-threshold"].asInt() : 0; | ||||
|   label_.set_markup(fmt::format(format, fmt::arg("temperatureC", temperature_c), | ||||
|   label_.set_markup(fmt::format(fmt::runtime(format), fmt::arg("temperatureC", temperature_c), | ||||
|                                 fmt::arg("temperatureF", temperature_f), | ||||
|                                 fmt::arg("temperatureK", temperature_k), | ||||
|                                 fmt::arg("icon", getIcon(temperature_c, "", max_temp)))); | ||||
| @@ -64,9 +64,9 @@ auto waybar::modules::Temperature::update() -> void { | ||||
|     if (config_["tooltip-format"].isString()) { | ||||
|       tooltip_format = config_["tooltip-format"].asString(); | ||||
|     } | ||||
|     label_.set_tooltip_text(fmt::format(tooltip_format, fmt::arg("temperatureC", temperature_c), | ||||
|                                         fmt::arg("temperatureF", temperature_f), | ||||
|                                         fmt::arg("temperatureK", temperature_k))); | ||||
|     label_.set_tooltip_text(fmt::format( | ||||
|         fmt::runtime(tooltip_format), fmt::arg("temperatureC", temperature_c), | ||||
|         fmt::arg("temperatureF", temperature_f), fmt::arg("temperatureK", temperature_k))); | ||||
|   } | ||||
|   // Call parent update | ||||
|   ALabel::update(); | ||||
|   | ||||
| @@ -336,8 +336,8 @@ auto UPower::update() -> void { | ||||
|       break; | ||||
|   } | ||||
|   std::string label_format = | ||||
|       fmt::format(showAltText ? format_alt : format, fmt::arg("percentage", percentString), | ||||
|                   fmt::arg("time", time_format)); | ||||
|       fmt::format(fmt::runtime(showAltText ? format_alt : format), | ||||
|                   fmt::arg("percentage", percentString), fmt::arg("time", time_format)); | ||||
|   // Only set the label text if it doesn't only contain spaces | ||||
|   bool onlySpaces = true; | ||||
|   for (auto& character : label_format) { | ||||
|   | ||||
| @@ -127,16 +127,16 @@ auto User::update() -> void { | ||||
|   auto startSystemTime = currentSystemTime - workSystemTimeSeconds; | ||||
|   long workSystemDays = uptimeSeconds / 86400; | ||||
|  | ||||
|   auto label = fmt::format(ALabel::format_, fmt::arg("up_H", fmt::format("{:%H}", startSystemTime)), | ||||
|                            fmt::arg("up_M", fmt::format("{:%M}", startSystemTime)), | ||||
|                            fmt::arg("up_d", fmt::format("{:%d}", startSystemTime)), | ||||
|                            fmt::arg("up_m", fmt::format("{:%m}", startSystemTime)), | ||||
|                            fmt::arg("up_Y", fmt::format("{:%Y}", startSystemTime)), | ||||
|                            fmt::arg("work_d", workSystemDays), | ||||
|                            fmt::arg("work_H", fmt::format("{:%H}", workSystemTimeSeconds)), | ||||
|                            fmt::arg("work_M", fmt::format("{:%M}", workSystemTimeSeconds)), | ||||
|                            fmt::arg("work_S", fmt::format("{:%S}", workSystemTimeSeconds)), | ||||
|                            fmt::arg("user", systemUser)); | ||||
|   auto label = fmt::format( | ||||
|       fmt::runtime(ALabel::format_), fmt::arg("up_H", fmt::format("{:%H}", startSystemTime)), | ||||
|       fmt::arg("up_M", fmt::format("{:%M}", startSystemTime)), | ||||
|       fmt::arg("up_d", fmt::format("{:%d}", startSystemTime)), | ||||
|       fmt::arg("up_m", fmt::format("{:%m}", startSystemTime)), | ||||
|       fmt::arg("up_Y", fmt::format("{:%Y}", startSystemTime)), fmt::arg("work_d", workSystemDays), | ||||
|       fmt::arg("work_H", fmt::format("{:%H}", workSystemTimeSeconds)), | ||||
|       fmt::arg("work_M", fmt::format("{:%M}", workSystemTimeSeconds)), | ||||
|       fmt::arg("work_S", fmt::format("{:%S}", workSystemTimeSeconds)), | ||||
|       fmt::arg("user", systemUser)); | ||||
|   ALabel::label_.set_markup(label); | ||||
|   AIconLabel::update(); | ||||
| } | ||||
|   | ||||
| @@ -279,7 +279,7 @@ auto waybar::modules::Wireplumber::update() -> void { | ||||
|     label_.get_style_context()->remove_class("muted"); | ||||
|   } | ||||
|  | ||||
|   std::string markup = fmt::format(format, fmt::arg("node_name", node_name_), | ||||
|   std::string markup = fmt::format(fmt::runtime(format), fmt::arg("node_name", node_name_), | ||||
|                                    fmt::arg("volume", volume_), fmt::arg("icon", getIcon(volume_))); | ||||
|   label_.set_markup(markup); | ||||
|  | ||||
| @@ -291,9 +291,9 @@ auto waybar::modules::Wireplumber::update() -> void { | ||||
|     } | ||||
|  | ||||
|     if (!tooltip_format.empty()) { | ||||
|       label_.set_tooltip_text(fmt::format(tooltip_format, fmt::arg("node_name", node_name_), | ||||
|                                           fmt::arg("volume", volume_), | ||||
|                                           fmt::arg("icon", getIcon(volume_)))); | ||||
|       label_.set_tooltip_text( | ||||
|           fmt::format(fmt::runtime(tooltip_format), fmt::arg("node_name", node_name_), | ||||
|                       fmt::arg("volume", volume_), fmt::arg("icon", getIcon(volume_)))); | ||||
|     } else { | ||||
|       label_.set_tooltip_text(node_name_); | ||||
|     } | ||||
|   | ||||
| @@ -618,9 +618,10 @@ void Task::update() { | ||||
|     app_id = Glib::Markup::escape_text(app_id); | ||||
|   } | ||||
|   if (!format_before_.empty()) { | ||||
|     auto txt = fmt::format(format_before_, fmt::arg("title", title), fmt::arg("name", name), | ||||
|                            fmt::arg("app_id", app_id), fmt::arg("state", state_string()), | ||||
|                            fmt::arg("short_state", state_string(true))); | ||||
|     auto txt = | ||||
|         fmt::format(fmt::runtime(format_before_), fmt::arg("title", title), fmt::arg("name", name), | ||||
|                     fmt::arg("app_id", app_id), fmt::arg("state", state_string()), | ||||
|                     fmt::arg("short_state", state_string(true))); | ||||
|     if (markup) | ||||
|       text_before_.set_markup(txt); | ||||
|     else | ||||
| @@ -628,9 +629,10 @@ void Task::update() { | ||||
|     text_before_.show(); | ||||
|   } | ||||
|   if (!format_after_.empty()) { | ||||
|     auto txt = fmt::format(format_after_, fmt::arg("title", title), fmt::arg("name", name), | ||||
|                            fmt::arg("app_id", app_id), fmt::arg("state", state_string()), | ||||
|                            fmt::arg("short_state", state_string(true))); | ||||
|     auto txt = | ||||
|         fmt::format(fmt::runtime(format_after_), fmt::arg("title", title), fmt::arg("name", name), | ||||
|                     fmt::arg("app_id", app_id), fmt::arg("state", state_string()), | ||||
|                     fmt::arg("short_state", state_string(true))); | ||||
|     if (markup) | ||||
|       text_after_.set_markup(txt); | ||||
|     else | ||||
| @@ -639,9 +641,10 @@ void Task::update() { | ||||
|   } | ||||
|  | ||||
|   if (!format_tooltip_.empty()) { | ||||
|     auto txt = fmt::format(format_tooltip_, fmt::arg("title", title), fmt::arg("name", name), | ||||
|                            fmt::arg("app_id", app_id), fmt::arg("state", state_string()), | ||||
|                            fmt::arg("short_state", state_string(true))); | ||||
|     auto txt = | ||||
|         fmt::format(fmt::runtime(format_tooltip_), fmt::arg("title", title), fmt::arg("name", name), | ||||
|                     fmt::arg("app_id", app_id), fmt::arg("state", state_string()), | ||||
|                     fmt::arg("short_state", state_string(true))); | ||||
|     if (markup) | ||||
|       button_.set_tooltip_markup(txt); | ||||
|     else | ||||
|   | ||||
| @@ -379,7 +379,7 @@ Workspace::~Workspace() { | ||||
| } | ||||
|  | ||||
| auto Workspace::update() -> void { | ||||
|   label_.set_markup(fmt::format(format_, fmt::arg("name", name_), | ||||
|   label_.set_markup(fmt::format(fmt::runtime(format_), fmt::arg("name", name_), | ||||
|                                 fmt::arg("icon", with_icon_ ? get_icon() : ""))); | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -2,7 +2,11 @@ | ||||
|  | ||||
| #include <glibmm.h> | ||||
|  | ||||
| #include <catch2/catch_all.hpp> | ||||
| #if __has_include(<catch2/catch_test_macros.hpp>) | ||||
| #include <catch2/catch_test_macros.hpp> | ||||
| #else | ||||
| #include <catch2/catch.hpp> | ||||
| #endif | ||||
| #include <thread> | ||||
| #include <type_traits> | ||||
|  | ||||
|   | ||||
| @@ -1,6 +1,10 @@ | ||||
| #include "config.hpp" | ||||
|  | ||||
| #include <catch2/catch_all.hpp> | ||||
| #if __has_include(<catch2/catch_test_macros.hpp>) | ||||
| #include <catch2/catch_test_macros.hpp> | ||||
| #else | ||||
| #include <catch2/catch.hpp> | ||||
| #endif | ||||
|  | ||||
| TEST_CASE("Load simple config", "[config]") { | ||||
|   waybar::Config conf; | ||||
|   | ||||
							
								
								
									
										162
									
								
								test/date.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										162
									
								
								test/date.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,162 @@ | ||||
| #include "util/date.hpp" | ||||
|  | ||||
| #include <chrono> | ||||
| #include <ctime> | ||||
| #include <iomanip> | ||||
| #include <sstream> | ||||
| #include <stdexcept> | ||||
|  | ||||
| #if __has_include(<catch2/catch_test_macros.hpp>) | ||||
| #include <catch2/catch_test_macros.hpp> | ||||
| #include <catch2/matchers/catch_matchers_all.hpp> | ||||
| #else | ||||
| #include <catch2/catch.hpp> | ||||
| #endif | ||||
|  | ||||
| #ifndef SKIP | ||||
| #define SKIP(...)    \ | ||||
|   WARN(__VA_ARGS__); \ | ||||
|   return | ||||
| #endif | ||||
|  | ||||
| using namespace std::literals::chrono_literals; | ||||
|  | ||||
| /* | ||||
|  * Check that the date/time formatter with locale and timezone support is working as expected. | ||||
|  */ | ||||
|  | ||||
| const date::zoned_time<std::chrono::seconds> TEST_TIME = date::zoned_time{ | ||||
|     "UTC", date::local_days{date::Monday[1] / date::January / 2022} + 13h + 4min + 5s}; | ||||
|  | ||||
| /* | ||||
|  * Check if the date formatted with LC_TIME=en_US is within expectations. | ||||
|  * | ||||
|  * The check expects Glibc output style and will fail with FreeBSD (different implementation) | ||||
|  * or musl (no implementation). | ||||
|  */ | ||||
| static const bool LC_TIME_is_sane = []() { | ||||
|   try { | ||||
|     std::stringstream ss; | ||||
|     ss.imbue(std::locale("en_US.UTF-8")); | ||||
|  | ||||
|     time_t t = 1641211200; | ||||
|     std::tm tm = *std::gmtime(&t); | ||||
|  | ||||
|     ss << std::put_time(&tm, "%x %X"); | ||||
|     return ss.str() == "01/03/2022 12:00:00 PM"; | ||||
|   } catch (std::exception &) { | ||||
|     return false; | ||||
|   } | ||||
| }(); | ||||
|  | ||||
| TEST_CASE("Format UTC time", "[clock][util]") { | ||||
|   const auto loc = std::locale("C"); | ||||
|   const auto tm = TEST_TIME; | ||||
|  | ||||
|   CHECK(fmt::format(loc, "{}", tm).empty());  // no format specified | ||||
|   CHECK(fmt::format(loc, "{:%c %Z}", tm) == "Mon Jan  3 13:04:05 2022 UTC"); | ||||
|   CHECK(fmt::format(loc, "{arg:%Y%m%d%H%M%S}", fmt::arg("arg", tm)) == "20220103130405"); | ||||
|  | ||||
|   if (!LC_TIME_is_sane) { | ||||
|     SKIP("Locale support check failed, skip tests"); | ||||
|   } | ||||
|  | ||||
|   /* Test a few locales that are most likely to be present */ | ||||
|   SECTION("US locale") { | ||||
|     try { | ||||
|       const auto loc = std::locale("en_US.UTF-8"); | ||||
|  | ||||
|       CHECK(fmt::format(loc, "{}", tm).empty());  // no format specified | ||||
|       CHECK_THAT(fmt::format(loc, "{:%c}", tm),   // HowardHinnant/date#704 | ||||
|                  Catch::Matchers::StartsWith("Mon 03 Jan 2022 01:04:05 PM")); | ||||
|       CHECK(fmt::format(loc, "{:%x %X}", tm) == "01/03/2022 01:04:05 PM"); | ||||
|       CHECK(fmt::format(loc, "{arg:%Y%m%d%H%M%S}", fmt::arg("arg", tm)) == "20220103130405"); | ||||
|     } catch (const std::runtime_error &) { | ||||
|       WARN("Locale en_US not found, skip tests"); | ||||
|     } | ||||
|   } | ||||
|   SECTION("GB locale") { | ||||
|     try { | ||||
|       const auto loc = std::locale("en_GB.UTF-8"); | ||||
|  | ||||
|       CHECK(fmt::format(loc, "{}", tm).empty());  // no format specified | ||||
|       CHECK_THAT(fmt::format(loc, "{:%c}", tm),   // HowardHinnant/date#704 | ||||
|                  Catch::Matchers::StartsWith("Mon 03 Jan 2022 13:04:05")); | ||||
|       CHECK(fmt::format(loc, "{:%x %X}", tm) == "03/01/22 13:04:05"); | ||||
|       CHECK(fmt::format(loc, "{arg:%Y%m%d%H%M%S}", fmt::arg("arg", tm)) == "20220103130405"); | ||||
|     } catch (const std::runtime_error &) { | ||||
|       WARN("Locale en_GB not found, skip tests"); | ||||
|     } | ||||
|   } | ||||
|   SECTION("Global locale") { | ||||
|     try { | ||||
|       const auto loc = std::locale::global(std::locale("en_US.UTF-8")); | ||||
|  | ||||
|       CHECK(fmt::format("{}", tm).empty());  // no format specified | ||||
|       CHECK_THAT(fmt::format("{:%c}", tm),   // HowardHinnant/date#704 | ||||
|                  Catch::Matchers::StartsWith("Mon 03 Jan 2022 01:04:05 PM")); | ||||
|       CHECK(fmt::format("{:%x %X}", tm) == "01/03/2022 01:04:05 PM"); | ||||
|       CHECK(fmt::format("{arg:%Y%m%d%H%M%S}", fmt::arg("arg", tm)) == "20220103130405"); | ||||
|  | ||||
|       std::locale::global(loc); | ||||
|     } catch (const std::runtime_error &) { | ||||
|       WARN("Locale en_US not found, skip tests"); | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
| TEST_CASE("Format zoned time", "[clock][util]") { | ||||
|   const auto loc = std::locale("C"); | ||||
|   const auto tm = date::zoned_time{"America/New_York", TEST_TIME}; | ||||
|  | ||||
|   CHECK(fmt::format(loc, "{}", tm).empty());  // no format specified | ||||
|   CHECK(fmt::format(loc, "{:%c %Z}", tm) == "Mon Jan  3 08:04:05 2022 EST"); | ||||
|   CHECK(fmt::format(loc, "{arg:%Y%m%d%H%M%S}", fmt::arg("arg", tm)) == "20220103080405"); | ||||
|  | ||||
|   if (!LC_TIME_is_sane) { | ||||
|     SKIP("Locale support check failed, skip tests"); | ||||
|   } | ||||
|  | ||||
|   /* Test a few locales that are most likely to be present */ | ||||
|   SECTION("US locale") { | ||||
|     try { | ||||
|       const auto loc = std::locale("en_US.UTF-8"); | ||||
|  | ||||
|       CHECK(fmt::format(loc, "{}", tm).empty());  // no format specified | ||||
|       CHECK_THAT(fmt::format(loc, "{:%c}", tm),   // HowardHinnant/date#704 | ||||
|                  Catch::Matchers::StartsWith("Mon 03 Jan 2022 08:04:05 AM")); | ||||
|       CHECK(fmt::format(loc, "{:%x %X}", tm) == "01/03/2022 08:04:05 AM"); | ||||
|       CHECK(fmt::format(loc, "{arg:%Y%m%d%H%M%S}", fmt::arg("arg", tm)) == "20220103080405"); | ||||
|     } catch (const std::runtime_error &) { | ||||
|       WARN("Locale en_US not found, skip tests"); | ||||
|     } | ||||
|   } | ||||
|   SECTION("GB locale") { | ||||
|     try { | ||||
|       const auto loc = std::locale("en_GB.UTF-8"); | ||||
|  | ||||
|       CHECK(fmt::format(loc, "{}", tm).empty());  // no format specified | ||||
|       CHECK_THAT(fmt::format(loc, "{:%c}", tm),   // HowardHinnant/date#704 | ||||
|                  Catch::Matchers::StartsWith("Mon 03 Jan 2022 08:04:05")); | ||||
|       CHECK(fmt::format(loc, "{:%x %X}", tm) == "03/01/22 08:04:05"); | ||||
|       CHECK(fmt::format(loc, "{arg:%Y%m%d%H%M%S}", fmt::arg("arg", tm)) == "20220103080405"); | ||||
|     } catch (const std::runtime_error &) { | ||||
|       WARN("Locale en_GB not found, skip tests"); | ||||
|     } | ||||
|   } | ||||
|   SECTION("Global locale") { | ||||
|     try { | ||||
|       const auto loc = std::locale::global(std::locale("en_US.UTF-8")); | ||||
|  | ||||
|       CHECK(fmt::format("{}", tm).empty());  // no format specified | ||||
|       CHECK_THAT(fmt::format("{:%c}", tm),   // HowardHinnant/date#704 | ||||
|                  Catch::Matchers::StartsWith("Mon 03 Jan 2022 08:04:05 AM")); | ||||
|       CHECK(fmt::format("{:%x %X}", tm) == "01/03/2022 08:04:05 AM"); | ||||
|       CHECK(fmt::format("{arg:%Y%m%d%H%M%S}", fmt::arg("arg", tm)) == "20220103080405"); | ||||
|  | ||||
|       std::locale::global(loc); | ||||
|     } catch (const std::runtime_error &) { | ||||
|       WARN("Locale en_US not found, skip tests"); | ||||
|     } | ||||
|   } | ||||
| } | ||||
| @@ -3,8 +3,13 @@ | ||||
| #include <spdlog/sinks/stdout_sinks.h> | ||||
| #include <spdlog/spdlog.h> | ||||
|  | ||||
| #if __has_include(<catch2/catch_all.hpp>) | ||||
| #include <catch2/catch_all.hpp> | ||||
| #include <catch2/reporters/catch_reporter_tap.hpp> | ||||
| #else | ||||
| #include <catch2/catch.hpp> | ||||
| #include <catch2/catch_reporter_tap.hpp> | ||||
| #endif | ||||
| #include <memory> | ||||
|  | ||||
| int main(int argc, char* argv[]) { | ||||
| @@ -13,10 +18,16 @@ int main(int argc, char* argv[]) { | ||||
|  | ||||
|   session.applyCommandLine(argc, argv); | ||||
|   const auto logger = spdlog::default_logger(); | ||||
| #if CATCH_VERSION_MAJOR >= 3 | ||||
|   for (const auto& spec : session.config().getReporterSpecs()) { | ||||
|     if (spec.name() == "tap") { | ||||
|     const auto& reporter_name = spec.name(); | ||||
| #else | ||||
|   { | ||||
|     const auto& reporter_name = session.config().getReporterName(); | ||||
| #endif | ||||
|     if (reporter_name == "tap") { | ||||
|       spdlog::set_pattern("# [%l] %v"); | ||||
|     } else if (spec.name() == "compact") { | ||||
|     } else if (reporter_name == "compact") { | ||||
|       logger->sinks().clear(); | ||||
|     } else { | ||||
|       logger->sinks().assign({std::make_shared<spdlog::sinks::stderr_sink_st>()}); | ||||
|   | ||||
| @@ -15,7 +15,7 @@ test_src = files( | ||||
|  | ||||
| if tz_dep.found() | ||||
|   test_dep += tz_dep | ||||
|   test_src += files('waybar_time.cpp') | ||||
|   test_src += files('date.cpp') | ||||
| endif | ||||
|  | ||||
| waybar_test = executable( | ||||
|   | ||||
| @@ -1,90 +0,0 @@ | ||||
| #include "util/waybar_time.hpp" | ||||
|  | ||||
| #include <date/date.h> | ||||
| #include <date/tz.h> | ||||
|  | ||||
| #include <catch2/catch_all.hpp> | ||||
| #include <chrono> | ||||
| #include <stdexcept> | ||||
|  | ||||
| using namespace std::literals::chrono_literals; | ||||
|  | ||||
| /* | ||||
|  * Check that the date/time formatter with locale and timezone support is working as expected. | ||||
|  */ | ||||
|  | ||||
| const date::zoned_time<std::chrono::seconds> TEST_TIME = date::make_zoned( | ||||
|     "UTC", date::local_days{date::Monday[1] / date::January / 2022} + 13h + 4min + 5s); | ||||
|  | ||||
| TEST_CASE("Format UTC time", "[clock][util]") { | ||||
|   waybar::waybar_time tm{std::locale("C"), TEST_TIME}; | ||||
|  | ||||
|   REQUIRE(fmt::format("{}", tm).empty());  // no format specified | ||||
|   REQUIRE(fmt::format("{:%c %Z}", tm) == "Mon Jan  3 13:04:05 2022 UTC"); | ||||
|   REQUIRE(fmt::format("{arg:%Y%m%d%H%M%S}", fmt::arg("arg", tm)) == "20220103130405"); | ||||
|  | ||||
|   /* Test a few locales that are most likely to be present */ | ||||
|   SECTION("US locale") { | ||||
|     try { | ||||
|       tm.locale = std::locale("en_US"); | ||||
|  | ||||
|       REQUIRE(fmt::format("{}", tm).empty());  // no format specified | ||||
|       REQUIRE_THAT(fmt::format("{:%c}", tm),   // HowardHinnant/date#704 | ||||
|                    Catch::Matchers::StartsWith("Mon 03 Jan 2022 01:04:05 PM")); | ||||
|       REQUIRE(fmt::format("{:%x %X}", tm) == "01/03/2022 01:04:05 PM"); | ||||
|       REQUIRE(fmt::format("{arg:%Y%m%d%H%M%S}", fmt::arg("arg", tm)) == "20220103130405"); | ||||
|     } catch (const std::runtime_error&) { | ||||
|       // locale not found; ignore | ||||
|     } | ||||
|   } | ||||
|   SECTION("GB locale") { | ||||
|     try { | ||||
|       tm.locale = std::locale("en_GB"); | ||||
|  | ||||
|       REQUIRE(fmt::format("{}", tm).empty());  // no format specified | ||||
|       REQUIRE_THAT(fmt::format("{:%c}", tm),   // HowardHinnant/date#704 | ||||
|                    Catch::Matchers::StartsWith("Mon 03 Jan 2022 13:04:05")); | ||||
|       REQUIRE(fmt::format("{:%x %X}", tm) == "03/01/22 13:04:05"); | ||||
|       REQUIRE(fmt::format("{arg:%Y%m%d%H%M%S}", fmt::arg("arg", tm)) == "20220103130405"); | ||||
|     } catch (const std::runtime_error&) { | ||||
|       // locale not found; ignore | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
| TEST_CASE("Format zoned time", "[clock][util]") { | ||||
|   waybar::waybar_time tm{std::locale("C"), date::make_zoned("America/New_York", TEST_TIME)}; | ||||
|  | ||||
|   REQUIRE(fmt::format("{}", tm).empty());  // no format specified | ||||
|   REQUIRE(fmt::format("{:%c %Z}", tm) == "Mon Jan  3 08:04:05 2022 EST"); | ||||
|   REQUIRE(fmt::format("{arg:%Y%m%d%H%M%S}", fmt::arg("arg", tm)) == "20220103080405"); | ||||
|  | ||||
|   /* Test a few locales that are most likely to be present */ | ||||
|   SECTION("US locale") { | ||||
|     try { | ||||
|       tm.locale = std::locale("en_US"); | ||||
|  | ||||
|       REQUIRE(fmt::format("{}", tm).empty());  // no format specified | ||||
|       REQUIRE_THAT(fmt::format("{:%c}", tm),   // HowardHinnant/date#704 | ||||
|                    Catch::Matchers::StartsWith("Mon 03 Jan 2022 08:04:05 AM")); | ||||
|       REQUIRE(fmt::format("{:%x %X}", tm) == "01/03/2022 08:04:05 AM"); | ||||
|       REQUIRE(fmt::format("{arg:%Y%m%d%H%M%S}", fmt::arg("arg", tm)) == "20220103080405"); | ||||
|     } catch (const std::runtime_error&) { | ||||
|       // locale not found; ignore | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   SECTION("GB locale") { | ||||
|     try { | ||||
|       tm.locale = std::locale("en_GB"); | ||||
|  | ||||
|       REQUIRE(fmt::format("{}", tm).empty());  // no format specified | ||||
|       REQUIRE_THAT(fmt::format("{:%c}", tm),   // HowardHinnant/date#704 | ||||
|                    Catch::Matchers::StartsWith("Mon 03 Jan 2022 08:04:05")); | ||||
|       REQUIRE(fmt::format("{:%x %X}", tm) == "03/01/22 08:04:05"); | ||||
|       REQUIRE(fmt::format("{arg:%Y%m%d%H%M%S}", fmt::arg("arg", tm)) == "20220103080405"); | ||||
|     } catch (const std::runtime_error&) { | ||||
|       // locale not found; ignore | ||||
|     } | ||||
|   } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user
	 Viktar Lukashonak
					Viktar Lukashonak